| 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 27 matching lines...) Expand all Loading... |
| 38 #ifndef _SHARED_PTR_H | 38 #ifndef _SHARED_PTR_H |
| 39 #include <google/protobuf/stubs/shared_ptr.h> | 39 #include <google/protobuf/stubs/shared_ptr.h> |
| 40 #endif | 40 #endif |
| 41 #include <string> | 41 #include <string> |
| 42 #include <utility> | 42 #include <utility> |
| 43 #include <vector> | 43 #include <vector> |
| 44 | 44 |
| 45 #include <google/protobuf/stubs/logging.h> | 45 #include <google/protobuf/stubs/logging.h> |
| 46 #include <google/protobuf/stubs/common.h> | 46 #include <google/protobuf/stubs/common.h> |
| 47 #include <google/protobuf/stubs/stringprintf.h> | 47 #include <google/protobuf/stubs/stringprintf.h> |
| 48 #include <google/protobuf/compiler/js/well_known_types_embed.h> | |
| 49 #include <google/protobuf/io/printer.h> | 48 #include <google/protobuf/io/printer.h> |
| 50 #include <google/protobuf/io/zero_copy_stream.h> | 49 #include <google/protobuf/io/zero_copy_stream.h> |
| 51 #include <google/protobuf/descriptor.pb.h> | 50 #include <google/protobuf/descriptor.pb.h> |
| 52 #include <google/protobuf/descriptor.h> | 51 #include <google/protobuf/descriptor.h> |
| 53 #include <google/protobuf/stubs/strutil.h> | 52 #include <google/protobuf/stubs/strutil.h> |
| 54 | 53 |
| 55 namespace google { | 54 namespace google { |
| 56 namespace protobuf { | 55 namespace protobuf { |
| 57 namespace compiler { | 56 namespace compiler { |
| 58 namespace js { | 57 namespace js { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 | 144 |
| 146 // Returns a copy of |filename| with any trailing ".protodevel" or ".proto | 145 // Returns a copy of |filename| with any trailing ".protodevel" or ".proto |
| 147 // suffix stripped. | 146 // suffix stripped. |
| 148 // TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc. | 147 // TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc. |
| 149 string StripProto(const string& filename) { | 148 string StripProto(const string& filename) { |
| 150 const char* suffix = HasSuffixString(filename, ".protodevel") | 149 const char* suffix = HasSuffixString(filename, ".protodevel") |
| 151 ? ".protodevel" : ".proto"; | 150 ? ".protodevel" : ".proto"; |
| 152 return StripSuffixString(filename, suffix); | 151 return StripSuffixString(filename, suffix); |
| 153 } | 152 } |
| 154 | 153 |
| 155 // Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript | 154 // Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript |
| 156 // file foo/bar/baz.js. | 155 // file foo/bar/baz.js. |
| 157 string GetJSFilename(const GeneratorOptions& options, const string& filename) { | 156 string GetJSFilename(const string& filename) { |
| 158 return StripProto(filename) + options.GetFileNameExtension(); | 157 return StripProto(filename) + "_pb.js"; |
| 159 } | 158 } |
| 160 | 159 |
| 161 // Given a filename like foo/bar/baz.proto, returns the root directory | 160 // Given a filename like foo/bar/baz.proto, returns the root directory |
| 162 // path ../../ | 161 // path ../../ |
| 163 string GetRootPath(const string& from_filename, const string& to_filename) { | 162 string GetRootPath(const string& filename) { |
| 164 if (to_filename.find("google/protobuf") == 0) { | 163 size_t slashes = std::count(filename.begin(), filename.end(), '/'); |
| 165 // Well-known types (.proto files in the google/protobuf directory) are | |
| 166 // assumed to come from the 'google-protobuf' npm package. We may want to | |
| 167 // generalize this exception later by letting others put generated code in | |
| 168 // their own npm packages. | |
| 169 return "google-protobuf/"; | |
| 170 } | |
| 171 | |
| 172 size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/'); | |
| 173 if (slashes == 0) { | 164 if (slashes == 0) { |
| 174 return "./"; | 165 return "./"; |
| 175 } | 166 } |
| 176 string result = ""; | 167 string result = ""; |
| 177 for (size_t i = 0; i < slashes; i++) { | 168 for (size_t i = 0; i < slashes; i++) { |
| 178 result += "../"; | 169 result += "../"; |
| 179 } | 170 } |
| 180 return result; | 171 return result; |
| 181 } | 172 } |
| 182 | 173 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 202 const FileDescriptor* file) { | 193 const FileDescriptor* file) { |
| 203 if (!options.namespace_prefix.empty()) { | 194 if (!options.namespace_prefix.empty()) { |
| 204 return options.namespace_prefix; | 195 return options.namespace_prefix; |
| 205 } else if (!file->package().empty()) { | 196 } else if (!file->package().empty()) { |
| 206 return "proto." + file->package(); | 197 return "proto." + file->package(); |
| 207 } else { | 198 } else { |
| 208 return "proto"; | 199 return "proto"; |
| 209 } | 200 } |
| 210 } | 201 } |
| 211 | 202 |
| 212 // Returns the name of the message with a leading dot and taking into account | 203 // Forward declare, so that GetPrefix can call this method, |
| 213 // nesting, for example ".OuterMessage.InnerMessage", or returns empty if | 204 // which in turn, calls GetPrefix. |
| 214 // descriptor is null. This function does not handle namespacing, only message | 205 string GetPath(const GeneratorOptions& options, |
| 215 // nesting. | 206 const Descriptor* descriptor); |
| 216 string GetNestedMessageName(const Descriptor* descriptor) { | |
| 217 if (descriptor == NULL) { | |
| 218 return ""; | |
| 219 } | |
| 220 string result = | |
| 221 StripPrefixString(descriptor->full_name(), descriptor->file()->package()); | |
| 222 // Add a leading dot if one is not already present. | |
| 223 if (!result.empty() && result[0] != '.') { | |
| 224 result = "." + result; | |
| 225 } | |
| 226 return result; | |
| 227 } | |
| 228 | 207 |
| 229 // Returns the path prefix for a message or enumeration that | 208 // Returns the path prefix for a message or enumeration that |
| 230 // lives under the given file and containing type. | 209 // lives under the given file and containing type. |
| 231 string GetPrefix(const GeneratorOptions& options, | 210 string GetPrefix(const GeneratorOptions& options, |
| 232 const FileDescriptor* file_descriptor, | 211 const FileDescriptor* file_descriptor, |
| 233 const Descriptor* containing_type) { | 212 const Descriptor* containing_type) { |
| 234 string prefix = | 213 string prefix = ""; |
| 235 GetPath(options, file_descriptor) + GetNestedMessageName(containing_type); | 214 |
| 215 if (containing_type == NULL) { |
| 216 prefix = GetPath(options, file_descriptor); |
| 217 } else { |
| 218 prefix = GetPath(options, containing_type); |
| 219 } |
| 220 |
| 236 if (!prefix.empty()) { | 221 if (!prefix.empty()) { |
| 237 prefix += "."; | 222 prefix += "."; |
| 238 } | 223 } |
| 224 |
| 239 return prefix; | 225 return prefix; |
| 240 } | 226 } |
| 241 | 227 |
| 242 | 228 |
| 243 // Returns the fully normalized JavaScript path for the given | 229 // Returns the fully normalized JavaScript path for the given |
| 244 // message descriptor. | 230 // message descriptor. |
| 245 string GetPath(const GeneratorOptions& options, | 231 string GetPath(const GeneratorOptions& options, |
| 246 const Descriptor* descriptor) { | 232 const Descriptor* descriptor) { |
| 247 return GetPrefix( | 233 return GetPrefix( |
| 248 options, descriptor->file(), | 234 options, descriptor->file(), |
| (...skipping 23 matching lines...) Expand all Loading... |
| 272 string GetPath(const GeneratorOptions& options, | 258 string GetPath(const GeneratorOptions& options, |
| 273 const EnumValueDescriptor* value_descriptor) { | 259 const EnumValueDescriptor* value_descriptor) { |
| 274 return GetPath( | 260 return GetPath( |
| 275 options, | 261 options, |
| 276 value_descriptor->type()) + "." + value_descriptor->name(); | 262 value_descriptor->type()) + "." + value_descriptor->name(); |
| 277 } | 263 } |
| 278 | 264 |
| 279 string MaybeCrossFileRef(const GeneratorOptions& options, | 265 string MaybeCrossFileRef(const GeneratorOptions& options, |
| 280 const FileDescriptor* from_file, | 266 const FileDescriptor* from_file, |
| 281 const Descriptor* to_message) { | 267 const Descriptor* to_message) { |
| 282 if (options.import_style == GeneratorOptions::kImportCommonJs && | 268 if (options.import_style == GeneratorOptions::IMPORT_COMMONJS && |
| 283 from_file != to_message->file()) { | 269 from_file != to_message->file()) { |
| 284 // Cross-file ref in CommonJS needs to use the module alias instead of | 270 // Cross-file ref in CommonJS needs to use the module alias instead of |
| 285 // the global name. | 271 // the global name. |
| 286 return ModuleAlias(to_message->file()->name()) + | 272 return ModuleAlias(to_message->file()->name()) + "." + to_message->name(); |
| 287 GetNestedMessageName(to_message->containing_type()) + "." + | |
| 288 to_message->name(); | |
| 289 } else { | 273 } else { |
| 290 // Within a single file we use a full name. | 274 // Within a single file we use a full name. |
| 291 return GetPath(options, to_message); | 275 return GetPath(options, to_message); |
| 292 } | 276 } |
| 293 } | 277 } |
| 294 | 278 |
| 295 string SubmessageTypeRef(const GeneratorOptions& options, | 279 string SubmessageTypeRef(const GeneratorOptions& options, |
| 296 const FieldDescriptor* field) { | 280 const FieldDescriptor* field) { |
| 297 GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); | 281 GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); |
| 298 return MaybeCrossFileRef(options, field->file(), field->message_type()); | 282 return MaybeCrossFileRef(options, field->file(), field->message_type()); |
| 299 } | 283 } |
| 300 | 284 |
| 301 // - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields | 285 // - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields |
| 302 // (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate, | 286 // (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate, |
| 303 // and with reserved words triggering a "pb_" prefix. | 287 // and with reserved words triggering a "pb_" prefix. |
| 304 // - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields | 288 // - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields |
| 305 // (use the name directly), then append "List" if appropriate, then append "$" | 289 // (use the name directly), then append "List" if appropriate, then append "$" |
| 306 // if resulting name is equal to a reserved word. | 290 // if resulting name is equal to a reserved word. |
| 307 // - Enums: just uppercase. | 291 // - Enums: just uppercase. |
| 308 | 292 |
| 309 // 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. |
| 310 char ToLowerASCII(char c) { | 294 char ToLowerASCII(char c) { |
| 311 if (c >= 'A' && c <= 'Z') { | 295 if (c >= 'A' && c <= 'Z') { |
| 312 return (c - 'A') + 'a'; | 296 return (c - 'A') + 'a'; |
| 313 } else { | 297 } else { |
| 314 return c; | 298 return c; |
| 315 } | 299 } |
| 316 } | 300 } |
| 317 | 301 |
| 318 std::vector<string> ParseLowerUnderscore(const string& input) { | 302 vector<string> ParseLowerUnderscore(const string& input) { |
| 319 std::vector<string> words; | 303 vector<string> words; |
| 320 string running = ""; | 304 string running = ""; |
| 321 for (int i = 0; i < input.size(); i++) { | 305 for (int i = 0; i < input.size(); i++) { |
| 322 if (input[i] == '_') { | 306 if (input[i] == '_') { |
| 323 if (!running.empty()) { | 307 if (!running.empty()) { |
| 324 words.push_back(running); | 308 words.push_back(running); |
| 325 running.clear(); | 309 running.clear(); |
| 326 } | 310 } |
| 327 } else { | 311 } else { |
| 328 running += ToLowerASCII(input[i]); | 312 running += ToLowerASCII(input[i]); |
| 329 } | 313 } |
| 330 } | 314 } |
| 331 if (!running.empty()) { | 315 if (!running.empty()) { |
| 332 words.push_back(running); | 316 words.push_back(running); |
| 333 } | 317 } |
| 334 return words; | 318 return words; |
| 335 } | 319 } |
| 336 | 320 |
| 337 std::vector<string> ParseUpperCamel(const string& input) { | 321 vector<string> ParseUpperCamel(const string& input) { |
| 338 std::vector<string> words; | 322 vector<string> words; |
| 339 string running = ""; | 323 string running = ""; |
| 340 for (int i = 0; i < input.size(); i++) { | 324 for (int i = 0; i < input.size(); i++) { |
| 341 if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) { | 325 if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) { |
| 342 words.push_back(running); | 326 words.push_back(running); |
| 343 running.clear(); | 327 running.clear(); |
| 344 } | 328 } |
| 345 running += ToLowerASCII(input[i]); | 329 running += ToLowerASCII(input[i]); |
| 346 } | 330 } |
| 347 if (!running.empty()) { | 331 if (!running.empty()) { |
| 348 words.push_back(running); | 332 words.push_back(running); |
| 349 } | 333 } |
| 350 return words; | 334 return words; |
| 351 } | 335 } |
| 352 | 336 |
| 353 string ToLowerCamel(const std::vector<string>& words) { | 337 string ToLowerCamel(const vector<string>& words) { |
| 354 string result; | 338 string result; |
| 355 for (int i = 0; i < words.size(); i++) { | 339 for (int i = 0; i < words.size(); i++) { |
| 356 string word = words[i]; | 340 string word = words[i]; |
| 357 if (i == 0 && (word[0] >= 'A' && word[0] <= 'Z')) { | 341 if (i == 0 && (word[0] >= 'A' && word[0] <= 'Z')) { |
| 358 word[0] = (word[0] - 'A') + 'a'; | 342 word[0] = (word[0] - 'A') + 'a'; |
| 359 } else if (i != 0 && (word[0] >= 'a' && word[0] <= 'z')) { | 343 } else if (i != 0 && (word[0] >= 'a' && word[0] <= 'z')) { |
| 360 word[0] = (word[0] - 'a') + 'A'; | 344 word[0] = (word[0] - 'a') + 'A'; |
| 361 } | 345 } |
| 362 result += word; | 346 result += word; |
| 363 } | 347 } |
| 364 return result; | 348 return result; |
| 365 } | 349 } |
| 366 | 350 |
| 367 string ToUpperCamel(const std::vector<string>& words) { | 351 string ToUpperCamel(const vector<string>& words) { |
| 368 string result; | 352 string result; |
| 369 for (int i = 0; i < words.size(); i++) { | 353 for (int i = 0; i < words.size(); i++) { |
| 370 string word = words[i]; | 354 string word = words[i]; |
| 371 if (word[0] >= 'a' && word[0] <= 'z') { | 355 if (word[0] >= 'a' && word[0] <= 'z') { |
| 372 word[0] = (word[0] - 'a') + 'A'; | 356 word[0] = (word[0] - 'a') + 'A'; |
| 373 } | 357 } |
| 374 result += word; | 358 result += word; |
| 375 } | 359 } |
| 376 return result; | 360 return result; |
| 377 } | 361 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 406 } | 390 } |
| 407 } | 391 } |
| 408 | 392 |
| 409 return result; | 393 return result; |
| 410 } | 394 } |
| 411 | 395 |
| 412 // When we're generating one output file per type name, this is the filename | 396 // When we're generating one output file per type name, this is the filename |
| 413 // that top-level extensions should go in. | 397 // that top-level extensions should go in. |
| 414 string GetExtensionFileName(const GeneratorOptions& options, | 398 string GetExtensionFileName(const GeneratorOptions& options, |
| 415 const FileDescriptor* file) { | 399 const FileDescriptor* file) { |
| 416 return options.output_dir + "/" + ToFileName(GetPath(options, file)) + | 400 return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js"; |
| 417 options.GetFileNameExtension(); | |
| 418 } | 401 } |
| 419 | 402 |
| 420 // When we're generating one output file per type name, this is the filename | 403 // When we're generating one output file per type name, this is the filename |
| 421 // that a top-level message should go in. | 404 // that a top-level message should go in. |
| 422 string GetMessageFileName(const GeneratorOptions& options, | 405 string GetMessageFileName(const GeneratorOptions& options, |
| 423 const Descriptor* desc) { | 406 const Descriptor* desc) { |
| 424 return options.output_dir + "/" + ToFileName(desc->name()) + | 407 return options.output_dir + "/" + ToFileName(desc->name()) + ".js"; |
| 425 options.GetFileNameExtension(); | |
| 426 } | 408 } |
| 427 | 409 |
| 428 // When we're generating one output file per type name, this is the filename | 410 // When we're generating one output file per type name, this is the filename |
| 429 // that a top-level message should go in. | 411 // that a top-level message should go in. |
| 430 string GetEnumFileName(const GeneratorOptions& options, | 412 string GetEnumFileName(const GeneratorOptions& options, |
| 431 const EnumDescriptor* desc) { | 413 const EnumDescriptor* desc) { |
| 432 return options.output_dir + "/" + ToFileName(desc->name()) + | 414 return options.output_dir + "/" + ToFileName(desc->name()) + ".js"; |
| 433 options.GetFileNameExtension(); | |
| 434 } | 415 } |
| 435 | 416 |
| 436 // Returns the message/response ID, if set. | 417 // Returns the message/response ID, if set. |
| 437 string GetMessageId(const Descriptor* desc) { | 418 string GetMessageId(const Descriptor* desc) { |
| 438 return string(); | 419 return string(); |
| 439 } | 420 } |
| 440 | 421 |
| 441 bool IgnoreExtensionField(const FieldDescriptor* field) { | 422 bool IgnoreExtensionField(const FieldDescriptor* field) { |
| 442 // Exclude descriptor extensions from output "to avoid clutter" (from original | 423 // Exclude descriptor extensions from output "to avoid clutter" (from original |
| 443 // codegen). | 424 // codegen). |
| 444 return field->is_extension() && | 425 return field->is_extension() && |
| 445 field->containing_type()->file()->name() == | 426 field->containing_type()->file()->name() == |
| 446 "google/protobuf/descriptor.proto"; | 427 "google/protobuf/descriptor.proto"; |
| 447 } | 428 } |
| 448 | 429 |
| 449 | 430 |
| 450 // Used inside Google only -- do not remove. | 431 // Used inside Google only -- do not remove. |
| 451 bool IsResponse(const Descriptor* desc) { return false; } | 432 bool IsResponse(const Descriptor* desc) { return false; } |
| 452 | 433 |
| 453 bool IgnoreField(const FieldDescriptor* field) { | 434 bool IgnoreField(const FieldDescriptor* field) { |
| 454 return IgnoreExtensionField(field); | 435 return IgnoreExtensionField(field); |
| 455 } | 436 } |
| 456 | 437 |
| 457 | 438 |
| 458 // Used inside Google only -- do not remove. | |
| 459 bool ShouldTreatMapsAsRepeatedFields(const FileDescriptor& descriptor) { | |
| 460 return false; | |
| 461 } | |
| 462 | |
| 463 // Do we ignore this message type? | |
| 464 bool IgnoreMessage(const GeneratorOptions& options, const Descriptor* d) { | |
| 465 return d->options().map_entry() && | |
| 466 !ShouldTreatMapsAsRepeatedFields(*d->file()); | |
| 467 } | |
| 468 | |
| 469 bool IsMap(const GeneratorOptions& options, const FieldDescriptor* field) { | |
| 470 return field->is_map() && !ShouldTreatMapsAsRepeatedFields(*field->file()); | |
| 471 } | |
| 472 | |
| 473 // 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. |
| 474 bool IgnoreOneof(const OneofDescriptor* oneof) { | 440 bool IgnoreOneof(const OneofDescriptor* oneof) { |
| 475 for (int i = 0; i < oneof->field_count(); i++) { | 441 for (int i = 0; i < oneof->field_count(); i++) { |
| 476 if (!IgnoreField(oneof->field(i))) { | 442 if (!IgnoreField(oneof->field(i))) { |
| 477 return false; | 443 return false; |
| 478 } | 444 } |
| 479 } | 445 } |
| 480 return true; | 446 return true; |
| 481 } | 447 } |
| 482 | 448 |
| 483 string JSIdent(const GeneratorOptions& options, const FieldDescriptor* field, | 449 string JSIdent(const FieldDescriptor* field, |
| 484 bool is_upper_camel, bool is_map, bool drop_list) { | 450 bool is_upper_camel, |
| 451 bool is_map) { |
| 485 string result; | 452 string result; |
| 486 if (field->type() == FieldDescriptor::TYPE_GROUP) { | 453 if (field->type() == FieldDescriptor::TYPE_GROUP) { |
| 487 result = is_upper_camel ? | 454 result = is_upper_camel ? |
| 488 ToUpperCamel(ParseUpperCamel(field->message_type()->name())) : | 455 ToUpperCamel(ParseUpperCamel(field->message_type()->name())) : |
| 489 ToLowerCamel(ParseUpperCamel(field->message_type()->name())); | 456 ToLowerCamel(ParseUpperCamel(field->message_type()->name())); |
| 490 } else { | 457 } else { |
| 491 result = is_upper_camel ? | 458 result = is_upper_camel ? |
| 492 ToUpperCamel(ParseLowerUnderscore(field->name())) : | 459 ToUpperCamel(ParseLowerUnderscore(field->name())) : |
| 493 ToLowerCamel(ParseLowerUnderscore(field->name())); | 460 ToLowerCamel(ParseLowerUnderscore(field->name())); |
| 494 } | 461 } |
| 495 if (is_map || IsMap(options, field)) { | 462 if (is_map) { |
| 496 // JSPB-style or proto3-style map. | |
| 497 result += "Map"; | 463 result += "Map"; |
| 498 } else if (!drop_list && field->is_repeated()) { | 464 } else if (field->is_repeated()) { |
| 499 // Repeated field. | |
| 500 result += "List"; | 465 result += "List"; |
| 501 } | 466 } |
| 502 return result; | 467 return result; |
| 503 } | 468 } |
| 504 | 469 |
| 505 string JSObjectFieldName(const GeneratorOptions& options, | 470 string JSObjectFieldName(const FieldDescriptor* field) { |
| 506 const FieldDescriptor* field) { | 471 string name = JSIdent( |
| 507 string name = JSIdent(options, field, | 472 field, |
| 508 /* is_upper_camel = */ false, | 473 /* is_upper_camel = */ false, |
| 509 /* is_map = */ false, | 474 /* is_map = */ false); |
| 510 /* drop_list = */ false); | |
| 511 if (IsReserved(name)) { | 475 if (IsReserved(name)) { |
| 512 name = "pb_" + name; | 476 name = "pb_" + name; |
| 513 } | 477 } |
| 514 return name; | 478 return name; |
| 515 } | 479 } |
| 516 | 480 |
| 517 string JSByteGetterSuffix(BytesMode bytes_mode) { | 481 string JSByteGetterSuffix(BytesMode bytes_mode) { |
| 518 switch (bytes_mode) { | 482 switch (bytes_mode) { |
| 519 case BYTES_DEFAULT: | 483 case BYTES_DEFAULT: |
| 520 return ""; | 484 return ""; |
| 521 case BYTES_B64: | 485 case BYTES_B64: |
| 522 return "B64"; | 486 return "B64"; |
| 523 case BYTES_U8: | 487 case BYTES_U8: |
| 524 return "U8"; | 488 return "U8"; |
| 525 default: | 489 default: |
| 526 assert(false); | 490 assert(false); |
| 527 } | 491 } |
| 528 return ""; | |
| 529 } | 492 } |
| 530 | 493 |
| 531 // 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 |
| 532 // name, e.g. MyField for .getMyField(). | 495 // name, e.g. MyField for .getMyField(). |
| 533 string JSGetterName(const GeneratorOptions& options, | 496 string JSGetterName(const FieldDescriptor* field, |
| 534 const FieldDescriptor* field, | 497 BytesMode bytes_mode = BYTES_DEFAULT) { |
| 535 BytesMode bytes_mode = BYTES_DEFAULT, | 498 string name = JSIdent(field, |
| 536 bool drop_list = false) { | |
| 537 string name = JSIdent(options, field, | |
| 538 /* is_upper_camel = */ true, | 499 /* is_upper_camel = */ true, |
| 539 /* is_map = */ false, drop_list); | 500 /* is_map = */ false); |
| 540 if (field->type() == FieldDescriptor::TYPE_BYTES) { | 501 if (field->type() == FieldDescriptor::TYPE_BYTES) { |
| 541 string suffix = JSByteGetterSuffix(bytes_mode); | 502 string suffix = JSByteGetterSuffix(bytes_mode); |
| 542 if (!suffix.empty()) { | 503 if (!suffix.empty()) { |
| 543 name += "_as" + suffix; | 504 name += "_as" + suffix; |
| 544 } | 505 } |
| 545 } | 506 } |
| 546 if (name == "Extension" || name == "JsPbMessageId") { | 507 if (name == "Extension" || name == "JsPbMessageId") { |
| 547 // Avoid conflicts with base-class names. | 508 // Avoid conflicts with base-class names. |
| 548 name += "$"; | 509 name += "$"; |
| 549 } | 510 } |
| 550 return name; | 511 return name; |
| 551 } | 512 } |
| 552 | 513 |
| 553 string JSMapGetterName(const GeneratorOptions& options, | 514 string JSMapGetterName(const FieldDescriptor* field) { |
| 554 const FieldDescriptor* field) { | 515 return JSIdent(field, |
| 555 return JSIdent(options, field, | |
| 556 /* is_upper_camel = */ true, | 516 /* is_upper_camel = */ true, |
| 557 /* is_map = */ true, | 517 /* is_map = */ true); |
| 558 /* drop_list = */ false); | |
| 559 } | 518 } |
| 560 | 519 |
| 561 | 520 |
| 562 | 521 |
| 563 string JSOneofName(const OneofDescriptor* oneof) { | 522 string JSOneofName(const OneofDescriptor* oneof) { |
| 564 return ToUpperCamel(ParseLowerUnderscore(oneof->name())); | 523 return ToUpperCamel(ParseLowerUnderscore(oneof->name())); |
| 565 } | 524 } |
| 566 | 525 |
| 567 // Returns the index corresponding to this field in the JSPB array (underlying | 526 // Returns the index corresponding to this field in the JSPB array (underlying |
| 568 // data storage array). | 527 // data storage array). |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 781 string DoubleToString(double value) { | 740 string DoubleToString(double value) { |
| 782 string result = SimpleDtoa(value); | 741 string result = SimpleDtoa(value); |
| 783 return PostProcessFloat(result); | 742 return PostProcessFloat(result); |
| 784 } | 743 } |
| 785 | 744 |
| 786 string MaybeNumberString(const FieldDescriptor* field, const string& orig) { | 745 string MaybeNumberString(const FieldDescriptor* field, const string& orig) { |
| 787 return orig; | 746 return orig; |
| 788 } | 747 } |
| 789 | 748 |
| 790 string JSFieldDefault(const FieldDescriptor* field) { | 749 string JSFieldDefault(const FieldDescriptor* field) { |
| 791 if (field->is_repeated()) { | 750 assert(field->has_default_value()); |
| 792 return "[]"; | |
| 793 } | |
| 794 | |
| 795 switch (field->cpp_type()) { | 751 switch (field->cpp_type()) { |
| 796 case FieldDescriptor::CPPTYPE_INT32: | 752 case FieldDescriptor::CPPTYPE_INT32: |
| 797 return MaybeNumberString( | 753 return MaybeNumberString( |
| 798 field, SimpleItoa(field->default_value_int32())); | 754 field, SimpleItoa(field->default_value_int32())); |
| 799 case FieldDescriptor::CPPTYPE_UINT32: | 755 case FieldDescriptor::CPPTYPE_UINT32: |
| 800 // The original codegen is in Java, and Java protobufs store unsigned | 756 // The original codegen is in Java, and Java protobufs store unsigned |
| 801 // integer values as signed integer values. In order to exactly match the | 757 // integer values as signed integer values. In order to exactly match the |
| 802 // output, we need to reinterpret as base-2 signed. Ugh. | 758 // output, we need to reinterpret as base-2 signed. Ugh. |
| 803 return MaybeNumberString( | 759 return MaybeNumberString( |
| 804 field, SimpleItoa(static_cast<int32>(field->default_value_uint32()))); | 760 field, SimpleItoa(static_cast<int32>(field->default_value_uint32()))); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 return JSStringTypeName(options, field, bytes_mode); | 882 return JSStringTypeName(options, field, bytes_mode); |
| 927 case FieldDescriptor::CPPTYPE_ENUM: | 883 case FieldDescriptor::CPPTYPE_ENUM: |
| 928 return GetPath(options, field->enum_type()); | 884 return GetPath(options, field->enum_type()); |
| 929 case FieldDescriptor::CPPTYPE_MESSAGE: | 885 case FieldDescriptor::CPPTYPE_MESSAGE: |
| 930 return GetPath(options, field->message_type()); | 886 return GetPath(options, field->message_type()); |
| 931 default: | 887 default: |
| 932 return ""; | 888 return ""; |
| 933 } | 889 } |
| 934 } | 890 } |
| 935 | 891 |
| 936 // Used inside Google only -- do not remove. | 892 bool HasFieldPresence(const FieldDescriptor* field); |
| 937 bool UseBrokenPresenceSemantics(const GeneratorOptions& options, | |
| 938 const FieldDescriptor* field) { | |
| 939 return false; | |
| 940 } | |
| 941 | |
| 942 // Returns true for fields that return "null" from accessors when they are | |
| 943 // unset. This should normally only be true for non-repeated submessages, but | |
| 944 // we have legacy users who relied on old behavior where accessors behaved this | |
| 945 // way. | |
| 946 bool ReturnsNullWhenUnset(const GeneratorOptions& options, | |
| 947 const FieldDescriptor* field) { | |
| 948 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && | |
| 949 field->is_optional()) { | |
| 950 return true; | |
| 951 } | |
| 952 | |
| 953 // TODO(haberman): remove this case and unconditionally return false. | |
| 954 return UseBrokenPresenceSemantics(options, field) && !field->is_repeated() && | |
| 955 !field->has_default_value(); | |
| 956 } | |
| 957 | |
| 958 // In a sane world, this would be the same as ReturnsNullWhenUnset(). But in | |
| 959 // the status quo, some fields declare that they never return null/undefined | |
| 960 // even though they actually do: | |
| 961 // * required fields | |
| 962 // * optional enum fields | |
| 963 // * proto3 primitive fields. | |
| 964 bool DeclaredReturnTypeIsNullable(const GeneratorOptions& options, | |
| 965 const FieldDescriptor* field) { | |
| 966 if (field->is_required() || field->type() == FieldDescriptor::TYPE_ENUM) { | |
| 967 return false; | |
| 968 } | |
| 969 | |
| 970 if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && | |
| 971 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { | |
| 972 return false; | |
| 973 } | |
| 974 | |
| 975 return ReturnsNullWhenUnset(options, field); | |
| 976 } | |
| 977 | |
| 978 bool SetterAcceptsUndefined(const GeneratorOptions& options, | |
| 979 const FieldDescriptor* field) { | |
| 980 if (ReturnsNullWhenUnset(options, field)) { | |
| 981 return true; | |
| 982 } | |
| 983 | |
| 984 // Broken presence semantics always accepts undefined for setters. | |
| 985 return UseBrokenPresenceSemantics(options, field); | |
| 986 } | |
| 987 | |
| 988 bool SetterAcceptsNull(const GeneratorOptions& options, | |
| 989 const FieldDescriptor* field) { | |
| 990 if (ReturnsNullWhenUnset(options, field)) { | |
| 991 return true; | |
| 992 } | |
| 993 | |
| 994 // With broken presence semantics, fields with defaults accept "null" for | |
| 995 // setters, but other fields do not. This is a strange quirk of the old | |
| 996 // codegen. | |
| 997 return UseBrokenPresenceSemantics(options, field) && | |
| 998 field->has_default_value(); | |
| 999 } | |
| 1000 | |
| 1001 // Returns types which are known to by non-nullable by default. | |
| 1002 // The style guide requires that we omit "!" in this case. | |
| 1003 bool IsPrimitive(const string& type) { | |
| 1004 return type == "undefined" || type == "string" || type == "number" || | |
| 1005 type == "boolean"; | |
| 1006 } | |
| 1007 | 893 |
| 1008 string JSFieldTypeAnnotation(const GeneratorOptions& options, | 894 string JSFieldTypeAnnotation(const GeneratorOptions& options, |
| 1009 const FieldDescriptor* field, | 895 const FieldDescriptor* field, |
| 1010 bool is_setter_argument, | 896 bool force_optional, |
| 1011 bool force_present, | 897 bool force_present, |
| 1012 bool singular_if_not_packed, | 898 bool singular_if_not_packed, |
| 1013 BytesMode bytes_mode = BYTES_DEFAULT) { | 899 BytesMode bytes_mode = BYTES_DEFAULT) { |
| 1014 GOOGLE_CHECK(!(is_setter_argument && force_present)); | 900 bool is_primitive = |
| 901 (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && |
| 902 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE && |
| 903 (field->type() != FieldDescriptor::TYPE_BYTES || |
| 904 bytes_mode == BYTES_B64)); |
| 905 |
| 1015 string jstype = JSTypeName(options, field, bytes_mode); | 906 string jstype = JSTypeName(options, field, bytes_mode); |
| 1016 | 907 |
| 1017 if (field->is_repeated() && | 908 if (field->is_repeated() && |
| 1018 (field->is_packed() || !singular_if_not_packed)) { | 909 (field->is_packed() || !singular_if_not_packed)) { |
| 1019 if (field->type() == FieldDescriptor::TYPE_BYTES && | 910 if (field->type() == FieldDescriptor::TYPE_BYTES && |
| 1020 bytes_mode == BYTES_DEFAULT) { | 911 bytes_mode == BYTES_DEFAULT) { |
| 1021 jstype = "(Array<!Uint8Array>|Array<string>)"; | 912 jstype = "(Array<!Uint8Array>|Array<string>)"; |
| 1022 } else { | 913 } else { |
| 1023 if (!IsPrimitive(jstype)) { | 914 if (!is_primitive) { |
| 1024 jstype = "!" + jstype; | 915 jstype = "!" + jstype; |
| 1025 } | 916 } |
| 1026 jstype = "Array.<" + jstype + ">"; | 917 jstype = "Array.<" + jstype + ">"; |
| 1027 } | 918 } |
| 1028 } | 919 if (!force_optional) { |
| 1029 | 920 jstype = "!" + jstype; |
| 1030 bool is_null_or_undefined = false; | |
| 1031 | |
| 1032 if (is_setter_argument) { | |
| 1033 if (SetterAcceptsNull(options, field)) { | |
| 1034 jstype = "?" + jstype; | |
| 1035 is_null_or_undefined = true; | |
| 1036 } | |
| 1037 | |
| 1038 if (SetterAcceptsUndefined(options, field)) { | |
| 1039 jstype += "|undefined"; | |
| 1040 is_null_or_undefined = true; | |
| 1041 } | |
| 1042 } else if (force_present) { | |
| 1043 // Don't add null or undefined. | |
| 1044 } else { | |
| 1045 if (DeclaredReturnTypeIsNullable(options, field)) { | |
| 1046 jstype = "?" + jstype; | |
| 1047 is_null_or_undefined = true; | |
| 1048 } | 921 } |
| 1049 } | 922 } |
| 1050 | 923 |
| 1051 if (!is_null_or_undefined && !IsPrimitive(jstype)) { | 924 if (field->is_optional() && is_primitive && |
| 925 (!field->has_default_value() || force_optional) && !force_present) { |
| 926 jstype += "?"; |
| 927 } else if (field->is_required() && !is_primitive && !force_optional) { |
| 1052 jstype = "!" + jstype; | 928 jstype = "!" + jstype; |
| 1053 } | 929 } |
| 1054 | 930 |
| 931 if (force_optional && HasFieldPresence(field)) { |
| 932 jstype += "|undefined"; |
| 933 } |
| 934 if (force_present && jstype[0] != '!' && !is_primitive) { |
| 935 jstype = "!" + jstype; |
| 936 } |
| 937 |
| 1055 return jstype; | 938 return jstype; |
| 1056 } | 939 } |
| 1057 | 940 |
| 1058 string JSBinaryReaderMethodType(const FieldDescriptor* field) { | 941 string JSBinaryReaderMethodType(const FieldDescriptor* field) { |
| 1059 string name = field->type_name(); | 942 string name = field->type_name(); |
| 1060 if (name[0] >= 'a' && name[0] <= 'z') { | 943 if (name[0] >= 'a' && name[0] <= 'z') { |
| 1061 name[0] = (name[0] - 'a') + 'A'; | 944 name[0] = (name[0] - 'a') + 'A'; |
| 1062 } | 945 } |
| 1063 | 946 |
| 1064 return name; | 947 return name; |
| 1065 } | 948 } |
| 1066 | 949 |
| 1067 string JSBinaryReadWriteMethodName(const FieldDescriptor* field, | 950 string JSBinaryReadWriteMethodName(const FieldDescriptor* field, |
| 1068 bool is_writer) { | 951 bool is_writer) { |
| 1069 string name = JSBinaryReaderMethodType(field); | 952 string name = JSBinaryReaderMethodType(field); |
| 1070 if (field->is_packed()) { | 953 if (field->is_packed()) { |
| 1071 name = "Packed" + name; | 954 name = "Packed" + name; |
| 1072 } else if (is_writer && field->is_repeated()) { | 955 } else if (is_writer && field->is_repeated()) { |
| 1073 name = "Repeated" + name; | 956 name = "Repeated" + name; |
| 1074 } | 957 } |
| 1075 return name; | 958 return name; |
| 1076 } | 959 } |
| 1077 | 960 |
| 1078 string JSBinaryReaderMethodName(const GeneratorOptions& options, | 961 string JSBinaryReaderMethodName(const FieldDescriptor* field) { |
| 1079 const FieldDescriptor* field) { | 962 return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false); |
| 1080 return "jspb.BinaryReader.prototype.read" + | |
| 1081 JSBinaryReadWriteMethodName(field, /* is_writer = */ false); | |
| 1082 } | 963 } |
| 1083 | 964 |
| 1084 string JSBinaryWriterMethodName(const GeneratorOptions& options, | 965 string JSBinaryWriterMethodName(const FieldDescriptor* field) { |
| 1085 const FieldDescriptor* field) { | 966 return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true); |
| 1086 return "jspb.BinaryWriter.prototype.write" + | |
| 1087 JSBinaryReadWriteMethodName(field, /* is_writer = */ true); | |
| 1088 } | 967 } |
| 1089 | 968 |
| 1090 string JSReturnClause(const FieldDescriptor* desc) { | 969 string JSReturnClause(const FieldDescriptor* desc) { |
| 1091 return ""; | 970 return ""; |
| 1092 } | 971 } |
| 1093 | 972 |
| 1094 string JSReturnDoc(const GeneratorOptions& options, | 973 string JSReturnDoc(const GeneratorOptions& options, |
| 1095 const FieldDescriptor* desc) { | 974 const FieldDescriptor* desc) { |
| 1096 return ""; | 975 return ""; |
| 1097 } | 976 } |
| 1098 | 977 |
| 1099 bool HasRepeatedFields(const GeneratorOptions& options, | 978 bool HasRepeatedFields(const Descriptor* desc) { |
| 1100 const Descriptor* desc) { | |
| 1101 for (int i = 0; i < desc->field_count(); i++) { | 979 for (int i = 0; i < desc->field_count(); i++) { |
| 1102 if (desc->field(i)->is_repeated() && !IsMap(options, desc->field(i))) { | 980 if (desc->field(i)->is_repeated()) { |
| 1103 return true; | 981 return true; |
| 1104 } | 982 } |
| 1105 } | 983 } |
| 1106 return false; | 984 return false; |
| 1107 } | 985 } |
| 1108 | 986 |
| 1109 static const char* kRepeatedFieldArrayName = ".repeatedFields_"; | 987 static const char* kRepeatedFieldArrayName = ".repeatedFields_"; |
| 1110 | 988 |
| 1111 string RepeatedFieldsArrayName(const GeneratorOptions& options, | 989 string RepeatedFieldsArrayName(const GeneratorOptions& options, |
| 1112 const Descriptor* desc) { | 990 const Descriptor* desc) { |
| 1113 return HasRepeatedFields(options, desc) | 991 return HasRepeatedFields(desc) ? |
| 1114 ? (GetPath(options, desc) + kRepeatedFieldArrayName) | 992 (GetPath(options, desc) + kRepeatedFieldArrayName) : "null"; |
| 1115 : "null"; | |
| 1116 } | 993 } |
| 1117 | 994 |
| 1118 bool HasOneofFields(const Descriptor* desc) { | 995 bool HasOneofFields(const Descriptor* desc) { |
| 1119 for (int i = 0; i < desc->field_count(); i++) { | 996 for (int i = 0; i < desc->field_count(); i++) { |
| 1120 if (desc->field(i)->containing_oneof()) { | 997 if (desc->field(i)->containing_oneof()) { |
| 1121 return true; | 998 return true; |
| 1122 } | 999 } |
| 1123 } | 1000 } |
| 1124 return false; | 1001 return false; |
| 1125 } | 1002 } |
| 1126 | 1003 |
| 1127 static const char* kOneofGroupArrayName = ".oneofGroups_"; | 1004 static const char* kOneofGroupArrayName = ".oneofGroups_"; |
| 1128 | 1005 |
| 1129 string OneofFieldsArrayName(const GeneratorOptions& options, | 1006 string OneofFieldsArrayName(const GeneratorOptions& options, |
| 1130 const Descriptor* desc) { | 1007 const Descriptor* desc) { |
| 1131 return HasOneofFields(desc) ? | 1008 return HasOneofFields(desc) ? |
| 1132 (GetPath(options, desc) + kOneofGroupArrayName) : "null"; | 1009 (GetPath(options, desc) + kOneofGroupArrayName) : "null"; |
| 1133 } | 1010 } |
| 1134 | 1011 |
| 1135 string RepeatedFieldNumberList(const GeneratorOptions& options, | 1012 string RepeatedFieldNumberList(const Descriptor* desc) { |
| 1136 const Descriptor* desc) { | |
| 1137 std::vector<string> numbers; | 1013 std::vector<string> numbers; |
| 1138 for (int i = 0; i < desc->field_count(); i++) { | 1014 for (int i = 0; i < desc->field_count(); i++) { |
| 1139 if (desc->field(i)->is_repeated() && !IsMap(options, desc->field(i))) { | 1015 if (desc->field(i)->is_repeated()) { |
| 1140 numbers.push_back(JSFieldIndex(desc->field(i))); | 1016 numbers.push_back(JSFieldIndex(desc->field(i))); |
| 1141 } | 1017 } |
| 1142 } | 1018 } |
| 1143 return "[" + Join(numbers, ",") + "]"; | 1019 return "[" + Join(numbers, ",") + "]"; |
| 1144 } | 1020 } |
| 1145 | 1021 |
| 1146 string OneofGroupList(const Descriptor* desc) { | 1022 string OneofGroupList(const Descriptor* desc) { |
| 1147 // List of arrays (one per oneof), each of which is a list of field indices | 1023 // List of arrays (one per oneof), each of which is a list of field indices |
| 1148 std::vector<string> oneof_entries; | 1024 std::vector<string> oneof_entries; |
| 1149 for (int i = 0; i < desc->oneof_decl_count(); i++) { | 1025 for (int i = 0; i < desc->oneof_decl_count(); i++) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1193 } | 1069 } |
| 1194 } | 1070 } |
| 1195 | 1071 |
| 1196 return type.substr(prefix); | 1072 return type.substr(prefix); |
| 1197 } | 1073 } |
| 1198 | 1074 |
| 1199 string JSExtensionsObjectName(const GeneratorOptions& options, | 1075 string JSExtensionsObjectName(const GeneratorOptions& options, |
| 1200 const FileDescriptor* from_file, | 1076 const FileDescriptor* from_file, |
| 1201 const Descriptor* desc) { | 1077 const Descriptor* desc) { |
| 1202 if (desc->full_name() == "google.protobuf.bridge.MessageSet") { | 1078 if (desc->full_name() == "google.protobuf.bridge.MessageSet") { |
| 1203 // TODO(haberman): fix this for the kImportCommonJs case. | 1079 // TODO(haberman): fix this for the IMPORT_COMMONJS case. |
| 1204 return "jspb.Message.messageSetExtensions"; | 1080 return "jspb.Message.messageSetExtensions"; |
| 1205 } else { | 1081 } else { |
| 1206 return MaybeCrossFileRef(options, from_file, desc) + ".extensions"; | 1082 return MaybeCrossFileRef(options, from_file, desc) + ".extensions"; |
| 1207 } | 1083 } |
| 1208 } | 1084 } |
| 1209 | 1085 |
| 1210 static const int kMapKeyField = 1; | |
| 1211 static const int kMapValueField = 2; | |
| 1212 | |
| 1213 const FieldDescriptor* MapFieldKey(const FieldDescriptor* field) { | |
| 1214 assert(field->is_map()); | |
| 1215 return field->message_type()->FindFieldByNumber(kMapKeyField); | |
| 1216 } | |
| 1217 | |
| 1218 const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) { | |
| 1219 assert(field->is_map()); | |
| 1220 return field->message_type()->FindFieldByNumber(kMapValueField); | |
| 1221 } | |
| 1222 | |
| 1223 string FieldDefinition(const GeneratorOptions& options, | 1086 string FieldDefinition(const GeneratorOptions& options, |
| 1224 const FieldDescriptor* field) { | 1087 const FieldDescriptor* field) { |
| 1225 if (IsMap(options, field)) { | 1088 string qualifier = field->is_repeated() ? "repeated" : |
| 1226 const FieldDescriptor* key_field = MapFieldKey(field); | 1089 (field->is_optional() ? "optional" : "required"); |
| 1227 const FieldDescriptor* value_field = MapFieldValue(field); | 1090 string type, name; |
| 1228 string key_type = ProtoTypeName(options, key_field); | 1091 if (field->type() == FieldDescriptor::TYPE_ENUM || |
| 1229 string value_type; | 1092 field->type() == FieldDescriptor::TYPE_MESSAGE) { |
| 1230 if (value_field->type() == FieldDescriptor::TYPE_ENUM || | 1093 type = RelativeTypeName(field); |
| 1231 value_field->type() == FieldDescriptor::TYPE_MESSAGE) { | 1094 name = field->name(); |
| 1232 value_type = RelativeTypeName(value_field); | 1095 } else if (field->type() == FieldDescriptor::TYPE_GROUP) { |
| 1233 } else { | 1096 type = "group"; |
| 1234 value_type = ProtoTypeName(options, value_field); | 1097 name = field->message_type()->name(); |
| 1235 } | |
| 1236 return StringPrintf("map<%s, %s> %s = %d;", | |
| 1237 key_type.c_str(), | |
| 1238 value_type.c_str(), | |
| 1239 field->name().c_str(), | |
| 1240 field->number()); | |
| 1241 } else { | 1098 } else { |
| 1242 string qualifier = field->is_repeated() ? "repeated" : | 1099 type = ProtoTypeName(options, field); |
| 1243 (field->is_optional() ? "optional" : "required"); | 1100 name = field->name(); |
| 1244 string type, name; | |
| 1245 if (field->type() == FieldDescriptor::TYPE_ENUM || | |
| 1246 field->type() == FieldDescriptor::TYPE_MESSAGE) { | |
| 1247 type = RelativeTypeName(field); | |
| 1248 name = field->name(); | |
| 1249 } else if (field->type() == FieldDescriptor::TYPE_GROUP) { | |
| 1250 type = "group"; | |
| 1251 name = field->message_type()->name(); | |
| 1252 } else { | |
| 1253 type = ProtoTypeName(options, field); | |
| 1254 name = field->name(); | |
| 1255 } | |
| 1256 return StringPrintf("%s %s %s = %d;", | |
| 1257 qualifier.c_str(), | |
| 1258 type.c_str(), | |
| 1259 name.c_str(), | |
| 1260 field->number()); | |
| 1261 } | 1101 } |
| 1102 return StringPrintf("%s %s %s = %d;", |
| 1103 qualifier.c_str(), |
| 1104 type.c_str(), |
| 1105 name.c_str(), |
| 1106 field->number()); |
| 1262 } | 1107 } |
| 1263 | 1108 |
| 1264 string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) { | 1109 string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) { |
| 1265 string comments; | 1110 string comments; |
| 1266 if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) { | 1111 if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) { |
| 1267 comments += | 1112 comments += |
| 1268 " * 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 " |
| 1269 "a Java server.\n" | 1114 "a Java server.\n" |
| 1270 " * You should avoid comparisons like {@code val === true/false} in " | 1115 " * You should avoid comparisons like {@code val === true/false} in " |
| 1271 "those cases.\n"; | 1116 "those cases.\n"; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1312 } | 1157 } |
| 1313 } | 1158 } |
| 1314 for (int i = 0; i < file->message_type_count(); i++) { | 1159 for (int i = 0; i < file->message_type_count(); i++) { |
| 1315 if (HasExtensions(file->message_type(i))) { | 1160 if (HasExtensions(file->message_type(i))) { |
| 1316 return true; | 1161 return true; |
| 1317 } | 1162 } |
| 1318 } | 1163 } |
| 1319 return false; | 1164 return false; |
| 1320 } | 1165 } |
| 1321 | 1166 |
| 1322 bool HasMap(const GeneratorOptions& options, const Descriptor* desc) { | |
| 1323 for (int i = 0; i < desc->field_count(); i++) { | |
| 1324 if (IsMap(options, desc->field(i))) { | |
| 1325 return true; | |
| 1326 } | |
| 1327 } | |
| 1328 for (int i = 0; i < desc->nested_type_count(); i++) { | |
| 1329 if (HasMap(options, desc->nested_type(i))) { | |
| 1330 return true; | |
| 1331 } | |
| 1332 } | |
| 1333 return false; | |
| 1334 } | |
| 1335 | |
| 1336 bool FileHasMap(const GeneratorOptions& options, const FileDescriptor* desc) { | |
| 1337 for (int i = 0; i < desc->message_type_count(); i++) { | |
| 1338 if (HasMap(options, desc->message_type(i))) { | |
| 1339 return true; | |
| 1340 } | |
| 1341 } | |
| 1342 return false; | |
| 1343 } | |
| 1344 | |
| 1345 bool IsExtendable(const Descriptor* desc) { | 1167 bool IsExtendable(const Descriptor* desc) { |
| 1346 return desc->extension_range_count() > 0; | 1168 return desc->extension_range_count() > 0; |
| 1347 } | 1169 } |
| 1348 | 1170 |
| 1349 // Returns the max index in the underlying data storage array beyond which the | 1171 // Returns the max index in the underlying data storage array beyond which the |
| 1350 // extension object is used. | 1172 // extension object is used. |
| 1351 string GetPivot(const Descriptor* desc) { | 1173 string GetPivot(const Descriptor* desc) { |
| 1352 static const int kDefaultPivot = (1 << 29); // max field number (29 bits) | 1174 static const int kDefaultPivot = (1 << 29); // max field number (29 bits) |
| 1353 | 1175 |
| 1354 // Find the max field number | 1176 // Find the max field number |
| 1355 int max_field_number = 0; | 1177 int max_field_number = 0; |
| 1356 for (int i = 0; i < desc->field_count(); i++) { | 1178 for (int i = 0; i < desc->field_count(); i++) { |
| 1357 if (!IgnoreField(desc->field(i)) && | 1179 if (!IgnoreField(desc->field(i)) && |
| 1358 desc->field(i)->number() > max_field_number) { | 1180 desc->field(i)->number() > max_field_number) { |
| 1359 max_field_number = desc->field(i)->number(); | 1181 max_field_number = desc->field(i)->number(); |
| 1360 } | 1182 } |
| 1361 } | 1183 } |
| 1362 | 1184 |
| 1363 int pivot = -1; | 1185 int pivot = -1; |
| 1364 if (IsExtendable(desc)) { | 1186 if (IsExtendable(desc)) { |
| 1365 pivot = ((max_field_number + 1) < kDefaultPivot) ? | 1187 pivot = ((max_field_number + 1) < kDefaultPivot) ? |
| 1366 (max_field_number + 1) : kDefaultPivot; | 1188 (max_field_number + 1) : kDefaultPivot; |
| 1367 } | 1189 } |
| 1368 | 1190 |
| 1369 return SimpleItoa(pivot); | 1191 return SimpleItoa(pivot); |
| 1370 } | 1192 } |
| 1371 | 1193 |
| 1372 // Whether this field represents presence. For fields with presence, we | 1194 // Returns true for fields that represent "null" as distinct from the default |
| 1373 // generate extra methods (clearFoo() and hasFoo()) for this field. | 1195 // value. See http://go/proto3#heading=h.kozewqqcqhuz for more information. |
| 1374 bool HasFieldPresence(const GeneratorOptions& options, | 1196 bool HasFieldPresence(const FieldDescriptor* field) { |
| 1375 const FieldDescriptor* field) { | 1197 return |
| 1376 if (field->is_repeated() || field->is_map()) { | 1198 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) || |
| 1377 // We say repeated fields and maps don't have presence, but we still do | 1199 (field->containing_oneof() != NULL) || |
| 1378 // generate clearFoo() methods for them through a special case elsewhere. | 1200 (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3); |
| 1379 return false; | 1201 } |
| 1202 |
| 1203 // For proto3 fields without presence, returns a string representing the default |
| 1204 // value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more |
| 1205 // information. |
| 1206 string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) { |
| 1207 switch (field->cpp_type()) { |
| 1208 case FieldDescriptor::CPPTYPE_INT32: |
| 1209 case FieldDescriptor::CPPTYPE_INT64: |
| 1210 case FieldDescriptor::CPPTYPE_UINT32: |
| 1211 case FieldDescriptor::CPPTYPE_UINT64: { |
| 1212 return "0"; |
| 1213 } |
| 1214 |
| 1215 case FieldDescriptor::CPPTYPE_ENUM: |
| 1216 case FieldDescriptor::CPPTYPE_FLOAT: |
| 1217 case FieldDescriptor::CPPTYPE_DOUBLE: |
| 1218 return "0"; |
| 1219 |
| 1220 case FieldDescriptor::CPPTYPE_BOOL: |
| 1221 return "false"; |
| 1222 |
| 1223 case FieldDescriptor::CPPTYPE_STRING: // includes BYTES |
| 1224 return "\"\""; |
| 1225 |
| 1226 default: |
| 1227 // MESSAGE is handled separately. |
| 1228 assert(false); |
| 1229 return ""; |
| 1380 } | 1230 } |
| 1381 | |
| 1382 if (UseBrokenPresenceSemantics(options, field)) { | |
| 1383 // Proto3 files with broken presence semantics have field presence. | |
| 1384 return true; | |
| 1385 } | |
| 1386 | |
| 1387 return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || | |
| 1388 field->containing_oneof() != NULL || | |
| 1389 field->file()->syntax() == FileDescriptor::SYNTAX_PROTO2; | |
| 1390 } | 1231 } |
| 1391 | 1232 |
| 1392 // We use this to implement the semantics that same file can be generated | 1233 // We use this to implement the semantics that same file can be generated |
| 1393 // multiple times, but the last one wins. We never actually write the files, | 1234 // multiple times, but the last one wins. We never actually write the files, |
| 1394 // but we keep a set of which descriptors were the final one for a given | 1235 // but we keep a set of which descriptors were the final one for a given |
| 1395 // filename. | 1236 // filename. |
| 1396 class FileDeduplicator { | 1237 class FileDeduplicator { |
| 1397 public: | 1238 public: |
| 1398 explicit FileDeduplicator(const GeneratorOptions& options) | 1239 explicit FileDeduplicator(const GeneratorOptions& options) |
| 1399 : error_on_conflict_(options.error_on_name_conflict) {} | 1240 : error_on_conflict_(options.error_on_name_conflict) {} |
| 1400 | 1241 |
| 1401 bool AddFile(const string& filename, const void* desc, string* error) { | 1242 bool AddFile(const string& filename, const void* desc, string* error) { |
| 1402 if (descs_by_filename_.find(filename) != descs_by_filename_.end()) { | 1243 if (descs_by_filename_.find(filename) != descs_by_filename_.end()) { |
| 1403 if (error_on_conflict_) { | 1244 if (error_on_conflict_) { |
| 1404 *error = "Name conflict: file name " + filename + | 1245 *error = "Name conflict: file name " + filename + |
| 1405 " would be generated by two descriptors"; | 1246 " would be generated by two descriptors"; |
| 1406 return false; | 1247 return false; |
| 1407 } | 1248 } |
| 1408 allowed_descs_.erase(descs_by_filename_[filename]); | 1249 allowed_descs_.erase(descs_by_filename_[filename]); |
| 1409 } | 1250 } |
| 1410 | 1251 |
| 1411 descs_by_filename_[filename] = desc; | 1252 descs_by_filename_[filename] = desc; |
| 1412 allowed_descs_.insert(desc); | 1253 allowed_descs_.insert(desc); |
| 1413 return true; | 1254 return true; |
| 1414 } | 1255 } |
| 1415 | 1256 |
| 1416 void GetAllowedSet(std::set<const void*>* allowed_set) { | 1257 void GetAllowedSet(set<const void*>* allowed_set) { |
| 1417 *allowed_set = allowed_descs_; | 1258 *allowed_set = allowed_descs_; |
| 1418 } | 1259 } |
| 1419 | 1260 |
| 1420 private: | 1261 private: |
| 1421 bool error_on_conflict_; | 1262 bool error_on_conflict_; |
| 1422 std::map<string, const void*> descs_by_filename_; | 1263 map<string, const void*> descs_by_filename_; |
| 1423 std::set<const void*> allowed_descs_; | 1264 set<const void*> allowed_descs_; |
| 1424 }; | 1265 }; |
| 1425 | 1266 |
| 1426 void DepthFirstSearch(const FileDescriptor* file, | 1267 void DepthFirstSearch(const FileDescriptor* file, |
| 1427 std::vector<const FileDescriptor*>* list, | 1268 vector<const FileDescriptor*>* list, |
| 1428 std::set<const FileDescriptor*>* seen) { | 1269 set<const FileDescriptor*>* seen) { |
| 1429 if (!seen->insert(file).second) { | 1270 if (!seen->insert(file).second) { |
| 1430 return; | 1271 return; |
| 1431 } | 1272 } |
| 1432 | 1273 |
| 1433 // Add all dependencies. | 1274 // Add all dependencies. |
| 1434 for (int i = 0; i < file->dependency_count(); i++) { | 1275 for (int i = 0; i < file->dependency_count(); i++) { |
| 1435 DepthFirstSearch(file->dependency(i), list, seen); | 1276 DepthFirstSearch(file->dependency(i), list, seen); |
| 1436 } | 1277 } |
| 1437 | 1278 |
| 1438 // Add this file. | 1279 // Add this file. |
| 1439 list->push_back(file); | 1280 list->push_back(file); |
| 1440 } | 1281 } |
| 1441 | 1282 |
| 1442 // A functor for the predicate to remove_if() below. Returns true if a given | 1283 // A functor for the predicate to remove_if() below. Returns true if a given |
| 1443 // FileDescriptor is not in the given set. | 1284 // FileDescriptor is not in the given set. |
| 1444 class NotInSet { | 1285 class NotInSet { |
| 1445 public: | 1286 public: |
| 1446 explicit NotInSet(const std::set<const FileDescriptor*>& file_set) | 1287 explicit NotInSet(const set<const FileDescriptor*>& file_set) |
| 1447 : file_set_(file_set) {} | 1288 : file_set_(file_set) {} |
| 1448 | 1289 |
| 1449 bool operator()(const FileDescriptor* file) { | 1290 bool operator()(const FileDescriptor* file) { |
| 1450 return file_set_.count(file) == 0; | 1291 return file_set_.count(file) == 0; |
| 1451 } | 1292 } |
| 1452 | 1293 |
| 1453 private: | 1294 private: |
| 1454 const std::set<const FileDescriptor*>& file_set_; | 1295 const set<const FileDescriptor*>& file_set_; |
| 1455 }; | 1296 }; |
| 1456 | 1297 |
| 1457 // This function generates an ordering of the input FileDescriptors that matches | 1298 // This function generates an ordering of the input FileDescriptors that matches |
| 1458 // the logic of the old code generator. The order is significant because two | 1299 // the logic of the old code generator. The order is significant because two |
| 1459 // different input files can generate the same output file, and the last one | 1300 // different input files can generate the same output file, and the last one |
| 1460 // needs to win. | 1301 // needs to win. |
| 1461 void GenerateJspbFileOrder(const std::vector<const FileDescriptor*>& input, | 1302 void GenerateJspbFileOrder(const vector<const FileDescriptor*>& input, |
| 1462 std::vector<const FileDescriptor*>* ordered) { | 1303 vector<const FileDescriptor*>* ordered) { |
| 1463 // First generate an ordering of all reachable files (including dependencies) | 1304 // First generate an ordering of all reachable files (including dependencies) |
| 1464 // with depth-first search. This mimics the behavior of --include_imports, | 1305 // with depth-first search. This mimics the behavior of --include_imports, |
| 1465 // which is what the old codegen used. | 1306 // which is what the old codegen used. |
| 1466 ordered->clear(); | 1307 ordered->clear(); |
| 1467 std::set<const FileDescriptor*> seen; | 1308 set<const FileDescriptor*> seen; |
| 1468 std::set<const FileDescriptor*> input_set; | 1309 set<const FileDescriptor*> input_set; |
| 1469 for (int i = 0; i < input.size(); i++) { | 1310 for (int i = 0; i < input.size(); i++) { |
| 1470 DepthFirstSearch(input[i], ordered, &seen); | 1311 DepthFirstSearch(input[i], ordered, &seen); |
| 1471 input_set.insert(input[i]); | 1312 input_set.insert(input[i]); |
| 1472 } | 1313 } |
| 1473 | 1314 |
| 1474 // Now remove the entries that are not actually in our input list. | 1315 // Now remove the entries that are not actually in our input list. |
| 1475 ordered->erase( | 1316 ordered->erase( |
| 1476 std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)), | 1317 std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)), |
| 1477 ordered->end()); | 1318 ordered->end()); |
| 1478 } | 1319 } |
| 1479 | 1320 |
| 1480 // If we're generating code in file-per-type mode, avoid overwriting files | 1321 // If we're generating code in file-per-type mode, avoid overwriting files |
| 1481 // by choosing the last descriptor that writes each filename and permitting | 1322 // by choosing the last descriptor that writes each filename and permitting |
| 1482 // only those to generate code. | 1323 // only those to generate code. |
| 1483 | 1324 |
| 1484 bool GenerateJspbAllowedSet(const GeneratorOptions& options, | 1325 bool GenerateJspbAllowedSet(const GeneratorOptions& options, |
| 1485 const std::vector<const FileDescriptor*>& files, | 1326 const vector<const FileDescriptor*>& files, |
| 1486 std::set<const void*>* allowed_set, | 1327 set<const void*>* allowed_set, |
| 1487 string* error) { | 1328 string* error) { |
| 1488 std::vector<const FileDescriptor*> files_ordered; | 1329 vector<const FileDescriptor*> files_ordered; |
| 1489 GenerateJspbFileOrder(files, &files_ordered); | 1330 GenerateJspbFileOrder(files, &files_ordered); |
| 1490 | 1331 |
| 1491 // Choose the last descriptor for each filename. | 1332 // Choose the last descriptor for each filename. |
| 1492 FileDeduplicator dedup(options); | 1333 FileDeduplicator dedup(options); |
| 1493 for (int i = 0; i < files_ordered.size(); i++) { | 1334 for (int i = 0; i < files_ordered.size(); i++) { |
| 1494 for (int j = 0; j < files_ordered[i]->message_type_count(); j++) { | 1335 for (int j = 0; j < files_ordered[i]->message_type_count(); j++) { |
| 1495 const Descriptor* desc = files_ordered[i]->message_type(j); | 1336 const Descriptor* desc = files_ordered[i]->message_type(j); |
| 1496 if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) { | 1337 if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) { |
| 1497 return false; | 1338 return false; |
| 1498 } | 1339 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1546 for (int i = 0; i < file->message_type_count(); i++) { | 1387 for (int i = 0; i < file->message_type_count(); i++) { |
| 1547 FindProvidesForMessage(options, printer, file->message_type(i), provided); | 1388 FindProvidesForMessage(options, printer, file->message_type(i), provided); |
| 1548 } | 1389 } |
| 1549 for (int i = 0; i < file->enum_type_count(); i++) { | 1390 for (int i = 0; i < file->enum_type_count(); i++) { |
| 1550 FindProvidesForEnum(options, printer, file->enum_type(i), provided); | 1391 FindProvidesForEnum(options, printer, file->enum_type(i), provided); |
| 1551 } | 1392 } |
| 1552 } | 1393 } |
| 1553 | 1394 |
| 1554 void Generator::FindProvides(const GeneratorOptions& options, | 1395 void Generator::FindProvides(const GeneratorOptions& options, |
| 1555 io::Printer* printer, | 1396 io::Printer* printer, |
| 1556 const std::vector<const FileDescriptor*>& files, | 1397 const vector<const FileDescriptor*>& files, |
| 1557 std::set<string>* provided) const { | 1398 std::set<string>* provided) const { |
| 1558 for (int i = 0; i < files.size(); i++) { | 1399 for (int i = 0; i < files.size(); i++) { |
| 1559 FindProvidesForFile(options, printer, files[i], provided); | 1400 FindProvidesForFile(options, printer, files[i], provided); |
| 1560 } | 1401 } |
| 1561 | 1402 |
| 1562 printer->Print("\n"); | 1403 printer->Print("\n"); |
| 1563 } | 1404 } |
| 1564 | 1405 |
| 1565 void Generator::FindProvidesForMessage( | 1406 void Generator::FindProvidesForMessage( |
| 1566 const GeneratorOptions& options, | 1407 const GeneratorOptions& options, |
| 1567 io::Printer* printer, | 1408 io::Printer* printer, |
| 1568 const Descriptor* desc, | 1409 const Descriptor* desc, |
| 1569 std::set<string>* provided) const { | 1410 std::set<string>* provided) const { |
| 1570 if (IgnoreMessage(options, desc)) { | |
| 1571 return; | |
| 1572 } | |
| 1573 | |
| 1574 string name = GetPath(options, desc); | 1411 string name = GetPath(options, desc); |
| 1575 provided->insert(name); | 1412 provided->insert(name); |
| 1576 | 1413 |
| 1577 for (int i = 0; i < desc->enum_type_count(); i++) { | 1414 for (int i = 0; i < desc->enum_type_count(); i++) { |
| 1578 FindProvidesForEnum(options, printer, desc->enum_type(i), | 1415 FindProvidesForEnum(options, printer, desc->enum_type(i), |
| 1579 provided); | 1416 provided); |
| 1580 } | 1417 } |
| 1581 for (int i = 0; i < desc->nested_type_count(); i++) { | 1418 for (int i = 0; i < desc->nested_type_count(); i++) { |
| 1582 FindProvidesForMessage(options, printer, desc->nested_type(i), | 1419 FindProvidesForMessage(options, printer, desc->nested_type(i), |
| 1583 provided); | 1420 provided); |
| 1584 } | 1421 } |
| 1585 } | 1422 } |
| 1586 | 1423 |
| 1587 void Generator::FindProvidesForEnum(const GeneratorOptions& options, | 1424 void Generator::FindProvidesForEnum(const GeneratorOptions& options, |
| 1588 io::Printer* printer, | 1425 io::Printer* printer, |
| 1589 const EnumDescriptor* enumdesc, | 1426 const EnumDescriptor* enumdesc, |
| 1590 std::set<string>* provided) const { | 1427 std::set<string>* provided) const { |
| 1591 string name = GetPath(options, enumdesc); | 1428 string name = GetPath(options, enumdesc); |
| 1592 provided->insert(name); | 1429 provided->insert(name); |
| 1593 } | 1430 } |
| 1594 | 1431 |
| 1595 void Generator::FindProvidesForFields( | 1432 void Generator::FindProvidesForFields( |
| 1596 const GeneratorOptions& options, | 1433 const GeneratorOptions& options, |
| 1597 io::Printer* printer, | 1434 io::Printer* printer, |
| 1598 const std::vector<const FieldDescriptor*>& fields, | 1435 const vector<const FieldDescriptor*>& fields, |
| 1599 std::set<string>* provided) const { | 1436 std::set<string>* provided) const { |
| 1600 for (int i = 0; i < fields.size(); i++) { | 1437 for (int i = 0; i < fields.size(); i++) { |
| 1601 const FieldDescriptor* field = fields[i]; | 1438 const FieldDescriptor* field = fields[i]; |
| 1602 | 1439 |
| 1603 if (IgnoreField(field)) { | 1440 if (IgnoreField(field)) { |
| 1604 continue; | 1441 continue; |
| 1605 } | 1442 } |
| 1606 | 1443 |
| 1607 string name = | 1444 string name = |
| 1608 GetPath(options, field->file()) + "." + | 1445 GetPath(options, field->file()) + "." + JSObjectFieldName(field); |
| 1609 JSObjectFieldName(options, field); | |
| 1610 provided->insert(name); | 1446 provided->insert(name); |
| 1611 } | 1447 } |
| 1612 } | 1448 } |
| 1613 | 1449 |
| 1614 void Generator::GenerateProvides(const GeneratorOptions& options, | 1450 void Generator::GenerateProvides(const GeneratorOptions& options, |
| 1615 io::Printer* printer, | 1451 io::Printer* printer, |
| 1616 std::set<string>* provided) const { | 1452 std::set<string>* provided) const { |
| 1617 for (std::set<string>::iterator it = provided->begin(); | 1453 for (std::set<string>::iterator it = provided->begin(); |
| 1618 it != provided->end(); ++it) { | 1454 it != provided->end(); ++it) { |
| 1619 if (options.import_style == GeneratorOptions::kImportClosure) { | 1455 printer->Print("goog.provide('$name$');\n", |
| 1620 printer->Print("goog.provide('$name$');\n", "name", *it); | 1456 "name", *it); |
| 1621 } else { | |
| 1622 // We aren't using Closure's import system, but we use goog.exportSymbol() | |
| 1623 // to construct the expected tree of objects, eg. | |
| 1624 // | |
| 1625 // goog.exportSymbol('foo.bar.Baz', null, this); | |
| 1626 // | |
| 1627 // // Later generated code expects foo.bar = {} to exist: | |
| 1628 // foo.bar.Baz = function() { /* ... */ } | |
| 1629 printer->Print("goog.exportSymbol('$name$', null, global);\n", "name", | |
| 1630 *it); | |
| 1631 } | |
| 1632 } | 1457 } |
| 1633 } | 1458 } |
| 1634 | 1459 |
| 1635 void Generator::GenerateRequiresForMessage(const GeneratorOptions& options, | 1460 void Generator::GenerateRequiresForMessage(const GeneratorOptions& options, |
| 1636 io::Printer* printer, | 1461 io::Printer* printer, |
| 1637 const Descriptor* desc, | 1462 const Descriptor* desc, |
| 1638 std::set<string>* provided) const { | 1463 std::set<string>* provided) const { |
| 1639 std::set<string> required; | 1464 std::set<string> required; |
| 1640 std::set<string> forwards; | 1465 std::set<string> forwards; |
| 1641 bool have_message = false; | 1466 bool have_message = false; |
| 1642 FindRequiresForMessage(options, desc, | 1467 FindRequiresForMessage(options, desc, |
| 1643 &required, &forwards, &have_message); | 1468 &required, &forwards, &have_message); |
| 1644 | 1469 |
| 1645 GenerateRequiresImpl(options, printer, &required, &forwards, provided, | 1470 GenerateRequiresImpl(options, printer, &required, &forwards, provided, |
| 1646 /* require_jspb = */ have_message, | 1471 /* require_jspb = */ have_message, |
| 1647 /* require_extension = */ HasExtensions(desc), | 1472 /* require_extension = */ HasExtensions(desc)); |
| 1648 /* require_map = */ HasMap(options, desc)); | |
| 1649 } | 1473 } |
| 1650 | 1474 |
| 1651 void Generator::GenerateRequiresForLibrary( | 1475 void Generator::GenerateRequiresForLibrary( |
| 1652 const GeneratorOptions& options, io::Printer* printer, | 1476 const GeneratorOptions& options, io::Printer* printer, |
| 1653 const std::vector<const FileDescriptor*>& files, | 1477 const vector<const FileDescriptor*>& files, |
| 1654 std::set<string>* provided) const { | 1478 std::set<string>* provided) const { |
| 1655 GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::kImportClosure); | 1479 GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::IMPORT_CLOSURE); |
| 1656 // For Closure imports we need to import every message type individually. | 1480 // For Closure imports we need to import every message type individually. |
| 1657 std::set<string> required; | 1481 std::set<string> required; |
| 1658 std::set<string> forwards; | 1482 std::set<string> forwards; |
| 1659 bool have_extensions = false; | 1483 bool have_extensions = false; |
| 1660 bool have_map = false; | |
| 1661 bool have_message = false; | 1484 bool have_message = false; |
| 1662 | 1485 |
| 1663 for (int i = 0; i < files.size(); i++) { | 1486 for (int i = 0; i < files.size(); i++) { |
| 1664 for (int j = 0; j < files[i]->message_type_count(); j++) { | 1487 for (int j = 0; j < files[i]->message_type_count(); j++) { |
| 1665 const Descriptor* desc = files[i]->message_type(j); | 1488 FindRequiresForMessage(options, |
| 1666 if (!IgnoreMessage(options, desc)) { | 1489 files[i]->message_type(j), |
| 1667 FindRequiresForMessage(options, desc, &required, &forwards, | 1490 &required, &forwards, &have_message); |
| 1668 &have_message); | |
| 1669 } | |
| 1670 } | 1491 } |
| 1671 | |
| 1672 if (!have_extensions && HasExtensions(files[i])) { | 1492 if (!have_extensions && HasExtensions(files[i])) { |
| 1673 have_extensions = true; | 1493 have_extensions = true; |
| 1674 } | 1494 } |
| 1675 | 1495 |
| 1676 if (!have_map && FileHasMap(options, files[i])) { | |
| 1677 have_map = true; | |
| 1678 } | |
| 1679 | |
| 1680 for (int j = 0; j < files[i]->extension_count(); j++) { | 1496 for (int j = 0; j < files[i]->extension_count(); j++) { |
| 1681 const FieldDescriptor* extension = files[i]->extension(j); | 1497 const FieldDescriptor* extension = files[i]->extension(j); |
| 1682 if (IgnoreField(extension)) { | 1498 if (IgnoreField(extension)) { |
| 1683 continue; | 1499 continue; |
| 1684 } | 1500 } |
| 1685 if (extension->containing_type()->full_name() != | 1501 if (extension->containing_type()->full_name() != |
| 1686 "google.protobuf.bridge.MessageSet") { | 1502 "google.protobuf.bridge.MessageSet") { |
| 1687 required.insert(GetPath(options, extension->containing_type())); | 1503 required.insert(GetPath(options, extension->containing_type())); |
| 1688 } | 1504 } |
| 1689 FindRequiresForField(options, extension, &required, &forwards); | 1505 FindRequiresForField(options, extension, &required, &forwards); |
| 1690 have_extensions = true; | 1506 have_extensions = true; |
| 1691 } | 1507 } |
| 1692 } | 1508 } |
| 1693 | 1509 |
| 1694 GenerateRequiresImpl(options, printer, &required, &forwards, provided, | 1510 GenerateRequiresImpl(options, printer, &required, &forwards, provided, |
| 1695 /* require_jspb = */ have_message, | 1511 /* require_jspb = */ have_message, |
| 1696 /* require_extension = */ have_extensions, | 1512 /* require_extension = */ have_extensions); |
| 1697 /* require_map = */ have_map); | |
| 1698 } | 1513 } |
| 1699 | 1514 |
| 1700 void Generator::GenerateRequiresForExtensions( | 1515 void Generator::GenerateRequiresForExtensions( |
| 1701 const GeneratorOptions& options, io::Printer* printer, | 1516 const GeneratorOptions& options, io::Printer* printer, |
| 1702 const std::vector<const FieldDescriptor*>& fields, | 1517 const vector<const FieldDescriptor*>& fields, |
| 1703 std::set<string>* provided) const { | 1518 std::set<string>* provided) const { |
| 1704 std::set<string> required; | 1519 std::set<string> required; |
| 1705 std::set<string> forwards; | 1520 std::set<string> forwards; |
| 1706 for (int i = 0; i < fields.size(); i++) { | 1521 for (int i = 0; i < fields.size(); i++) { |
| 1707 const FieldDescriptor* field = fields[i]; | 1522 const FieldDescriptor* field = fields[i]; |
| 1708 if (IgnoreField(field)) { | 1523 if (IgnoreField(field)) { |
| 1709 continue; | 1524 continue; |
| 1710 } | 1525 } |
| 1711 FindRequiresForExtension(options, field, &required, &forwards); | 1526 FindRequiresForExtension(options, field, &required, &forwards); |
| 1712 } | 1527 } |
| 1713 | 1528 |
| 1714 GenerateRequiresImpl(options, printer, &required, &forwards, provided, | 1529 GenerateRequiresImpl(options, printer, &required, &forwards, provided, |
| 1715 /* require_jspb = */ false, | 1530 /* require_jspb = */ false, |
| 1716 /* require_extension = */ fields.size() > 0, | 1531 /* require_extension = */ fields.size() > 0); |
| 1717 /* require_map = */ false); | |
| 1718 } | 1532 } |
| 1719 | 1533 |
| 1720 void Generator::GenerateRequiresImpl(const GeneratorOptions& options, | 1534 void Generator::GenerateRequiresImpl(const GeneratorOptions& options, |
| 1721 io::Printer* printer, | 1535 io::Printer* printer, |
| 1722 std::set<string>* required, | 1536 std::set<string>* required, |
| 1723 std::set<string>* forwards, | 1537 std::set<string>* forwards, |
| 1724 std::set<string>* provided, | 1538 std::set<string>* provided, |
| 1725 bool require_jspb, bool require_extension, | 1539 bool require_jspb, |
| 1726 bool require_map) const { | 1540 bool require_extension) const { |
| 1727 if (require_jspb) { | 1541 if (require_jspb) { |
| 1728 printer->Print( | 1542 printer->Print( |
| 1729 "goog.require('jspb.Message');\n" | 1543 "goog.require('jspb.Message');\n"); |
| 1730 "goog.require('jspb.BinaryReader');\n" | 1544 if (options.binary) { |
| 1731 "goog.require('jspb.BinaryWriter');\n"); | 1545 printer->Print( |
| 1546 "goog.require('jspb.BinaryReader');\n" |
| 1547 "goog.require('jspb.BinaryWriter');\n"); |
| 1548 } |
| 1732 } | 1549 } |
| 1733 if (require_extension) { | 1550 if (require_extension) { |
| 1734 printer->Print("goog.require('jspb.ExtensionFieldBinaryInfo');\n"); | |
| 1735 printer->Print( | 1551 printer->Print( |
| 1736 "goog.require('jspb.ExtensionFieldInfo');\n"); | 1552 "goog.require('jspb.ExtensionFieldInfo');\n"); |
| 1737 } | 1553 } |
| 1738 if (require_map) { | |
| 1739 printer->Print("goog.require('jspb.Map');\n"); | |
| 1740 } | |
| 1741 | 1554 |
| 1742 std::set<string>::iterator it; | 1555 std::set<string>::iterator it; |
| 1743 for (it = required->begin(); it != required->end(); ++it) { | 1556 for (it = required->begin(); it != required->end(); ++it) { |
| 1744 if (provided->find(*it) != provided->end()) { | 1557 if (provided->find(*it) != provided->end()) { |
| 1745 continue; | 1558 continue; |
| 1746 } | 1559 } |
| 1747 printer->Print("goog.require('$name$');\n", | 1560 printer->Print("goog.require('$name$');\n", |
| 1748 "name", *it); | 1561 "name", *it); |
| 1749 } | 1562 } |
| 1750 | 1563 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1803 if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && | 1616 if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && |
| 1804 // N.B.: file-level extensions with enum type do *not* create | 1617 // N.B.: file-level extensions with enum type do *not* create |
| 1805 // dependencies, as per original codegen. | 1618 // dependencies, as per original codegen. |
| 1806 !(field->is_extension() && field->extension_scope() == NULL)) { | 1619 !(field->is_extension() && field->extension_scope() == NULL)) { |
| 1807 if (options.add_require_for_enums) { | 1620 if (options.add_require_for_enums) { |
| 1808 required->insert(GetPath(options, field->enum_type())); | 1621 required->insert(GetPath(options, field->enum_type())); |
| 1809 } else { | 1622 } else { |
| 1810 forwards->insert(GetPath(options, field->enum_type())); | 1623 forwards->insert(GetPath(options, field->enum_type())); |
| 1811 } | 1624 } |
| 1812 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | 1625 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 1813 if (!IgnoreMessage(options, field->message_type())) { | 1626 required->insert(GetPath(options, field->message_type())); |
| 1814 required->insert(GetPath(options, field->message_type())); | |
| 1815 } | |
| 1816 } | 1627 } |
| 1817 } | 1628 } |
| 1818 | 1629 |
| 1819 void Generator::FindRequiresForExtension(const GeneratorOptions& options, | 1630 void Generator::FindRequiresForExtension(const GeneratorOptions& options, |
| 1820 const FieldDescriptor* field, | 1631 const FieldDescriptor* field, |
| 1821 std::set<string>* required, | 1632 std::set<string>* required, |
| 1822 std::set<string>* forwards) const { | 1633 std::set<string>* forwards) const { |
| 1823 if (field->containing_type()->full_name() != "google.protobuf.bridge.Message
Set") { | 1634 if (field->containing_type()->full_name() != "google.protobuf.bridge.Message
Set") { |
| 1824 required->insert(GetPath(options, field->containing_type())); | 1635 required->insert(GetPath(options, field->containing_type())); |
| 1825 } | 1636 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1841 GenerateClass(options, printer, file->message_type(i)); | 1652 GenerateClass(options, printer, file->message_type(i)); |
| 1842 } | 1653 } |
| 1843 for (int i = 0; i < file->enum_type_count(); i++) { | 1654 for (int i = 0; i < file->enum_type_count(); i++) { |
| 1844 GenerateEnum(options, printer, file->enum_type(i)); | 1655 GenerateEnum(options, printer, file->enum_type(i)); |
| 1845 } | 1656 } |
| 1846 } | 1657 } |
| 1847 | 1658 |
| 1848 void Generator::GenerateClass(const GeneratorOptions& options, | 1659 void Generator::GenerateClass(const GeneratorOptions& options, |
| 1849 io::Printer* printer, | 1660 io::Printer* printer, |
| 1850 const Descriptor* desc) const { | 1661 const Descriptor* desc) const { |
| 1851 if (IgnoreMessage(options, desc)) { | |
| 1852 return; | |
| 1853 } | |
| 1854 | |
| 1855 if (!NamespaceOnly(desc)) { | 1662 if (!NamespaceOnly(desc)) { |
| 1856 printer->Print("\n"); | 1663 printer->Print("\n"); |
| 1857 GenerateClassConstructor(options, printer, desc); | 1664 GenerateClassConstructor(options, printer, desc); |
| 1858 GenerateClassFieldInfo(options, printer, desc); | 1665 GenerateClassFieldInfo(options, printer, desc); |
| 1859 | 1666 |
| 1860 | 1667 |
| 1861 GenerateClassToObject(options, printer, desc); | 1668 GenerateClassToObject(options, printer, desc); |
| 1862 // These must come *before* the extension-field info generation in | 1669 if (options.binary) { |
| 1863 // GenerateClassRegistration so that references to the binary | 1670 // These must come *before* the extension-field info generation in |
| 1864 // serialization/deserialization functions may be placed in the extension | 1671 // GenerateClassRegistration so that references to the binary |
| 1865 // objects. | 1672 // serialization/deserialization functions may be placed in the extension |
| 1866 GenerateClassDeserializeBinary(options, printer, desc); | 1673 // objects. |
| 1867 GenerateClassSerializeBinary(options, printer, desc); | 1674 GenerateClassDeserializeBinary(options, printer, desc); |
| 1868 | 1675 GenerateClassSerializeBinary(options, printer, desc); |
| 1676 } |
| 1677 GenerateClassClone(options, printer, desc); |
| 1869 GenerateClassRegistration(options, printer, desc); | 1678 GenerateClassRegistration(options, printer, desc); |
| 1870 GenerateClassFields(options, printer, desc); | 1679 GenerateClassFields(options, printer, desc); |
| 1871 if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.Messa
geSet") { | 1680 if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.Messa
geSet") { |
| 1872 GenerateClassExtensionFieldInfo(options, printer, desc); | 1681 GenerateClassExtensionFieldInfo(options, printer, desc); |
| 1873 } | 1682 } |
| 1874 | 1683 |
| 1875 if (options.import_style != GeneratorOptions::kImportClosure) { | 1684 if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) { |
| 1876 for (int i = 0; i < desc->extension_count(); i++) { | 1685 for (int i = 0; i < desc->extension_count(); i++) { |
| 1877 GenerateExtension(options, printer, desc->extension(i)); | 1686 GenerateExtension(options, printer, desc->extension(i)); |
| 1878 } | 1687 } |
| 1879 } | 1688 } |
| 1880 } | 1689 } |
| 1881 | 1690 |
| 1882 // Recurse on nested types. | 1691 // Recurse on nested types. |
| 1883 for (int i = 0; i < desc->enum_type_count(); i++) { | 1692 for (int i = 0; i < desc->enum_type_count(); i++) { |
| 1884 GenerateEnum(options, printer, desc->enum_type(i)); | 1693 GenerateEnum(options, printer, desc->enum_type(i)); |
| 1885 } | 1694 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1923 "goog.inherits($classname$, jspb.Message);\n" | 1732 "goog.inherits($classname$, jspb.Message);\n" |
| 1924 "if (goog.DEBUG && !COMPILED) {\n" | 1733 "if (goog.DEBUG && !COMPILED) {\n" |
| 1925 " $classname$.displayName = '$classname$';\n" | 1734 " $classname$.displayName = '$classname$';\n" |
| 1926 "}\n", | 1735 "}\n", |
| 1927 "classname", GetPath(options, desc)); | 1736 "classname", GetPath(options, desc)); |
| 1928 } | 1737 } |
| 1929 | 1738 |
| 1930 void Generator::GenerateClassFieldInfo(const GeneratorOptions& options, | 1739 void Generator::GenerateClassFieldInfo(const GeneratorOptions& options, |
| 1931 io::Printer* printer, | 1740 io::Printer* printer, |
| 1932 const Descriptor* desc) const { | 1741 const Descriptor* desc) const { |
| 1933 if (HasRepeatedFields(options, desc)) { | 1742 if (HasRepeatedFields(desc)) { |
| 1934 printer->Print( | 1743 printer->Print( |
| 1935 "/**\n" | 1744 "/**\n" |
| 1936 " * List of repeated fields within this message type.\n" | 1745 " * List of repeated fields within this message type.\n" |
| 1937 " * @private {!Array<number>}\n" | 1746 " * @private {!Array<number>}\n" |
| 1938 " * @const\n" | 1747 " * @const\n" |
| 1939 " */\n" | 1748 " */\n" |
| 1940 "$classname$$rptfieldarray$ = $rptfields$;\n" | 1749 "$classname$$rptfieldarray$ = $rptfields$;\n" |
| 1941 "\n", | 1750 "\n", |
| 1942 "classname", GetPath(options, desc), | 1751 "classname", GetPath(options, desc), |
| 1943 "rptfieldarray", kRepeatedFieldArrayName, | 1752 "rptfieldarray", kRepeatedFieldArrayName, |
| 1944 "rptfields", RepeatedFieldNumberList(options, desc)); | 1753 "rptfields", RepeatedFieldNumberList(desc)); |
| 1945 } | 1754 } |
| 1946 | 1755 |
| 1947 if (HasOneofFields(desc)) { | 1756 if (HasOneofFields(desc)) { |
| 1948 printer->Print( | 1757 printer->Print( |
| 1949 "/**\n" | 1758 "/**\n" |
| 1950 " * Oneof group definitions for this message. Each group defines the " | 1759 " * Oneof group definitions for this message. Each group defines the " |
| 1951 "field\n" | 1760 "field\n" |
| 1952 " * numbers belonging to that group. When of these fields' value is " | 1761 " * numbers belonging to that group. When of these fields' value is " |
| 1953 "set, all\n" | 1762 "set, all\n" |
| 1954 " * other fields in the group are cleared. During deserialization, if " | 1763 " * other fields in the group are cleared. During deserialization, if " |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2103 " obj.$$jspbMessageInstance = msg;\n" | 1912 " obj.$$jspbMessageInstance = msg;\n" |
| 2104 " }\n" | 1913 " }\n" |
| 2105 " return obj;\n" | 1914 " return obj;\n" |
| 2106 "};\n" | 1915 "};\n" |
| 2107 "}\n" | 1916 "}\n" |
| 2108 "\n" | 1917 "\n" |
| 2109 "\n", | 1918 "\n", |
| 2110 "classname", GetPath(options, desc)); | 1919 "classname", GetPath(options, desc)); |
| 2111 } | 1920 } |
| 2112 | 1921 |
| 2113 void Generator::GenerateFieldValueExpression(io::Printer* printer, | |
| 2114 const char *obj_reference, | |
| 2115 const FieldDescriptor* field, | |
| 2116 bool use_default) const { | |
| 2117 bool is_float_or_double = | |
| 2118 field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || | |
| 2119 field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE; | |
| 2120 if (use_default) { | |
| 2121 if (is_float_or_double) { | |
| 2122 // Coerce "Nan" and "Infinity" to actual float values. | |
| 2123 // | |
| 2124 // This will change null to 0, but that doesn't matter since we're getting | |
| 2125 // with a default. | |
| 2126 printer->Print("+"); | |
| 2127 } | |
| 2128 | |
| 2129 printer->Print( | |
| 2130 "jspb.Message.getFieldWithDefault($obj$, $index$, $default$)", | |
| 2131 "obj", obj_reference, | |
| 2132 "index", JSFieldIndex(field), | |
| 2133 "default", JSFieldDefault(field)); | |
| 2134 } else { | |
| 2135 if (is_float_or_double) { | |
| 2136 if (field->is_required()) { | |
| 2137 // Use "+" to convert all fields to numeric (including null). | |
| 2138 printer->Print( | |
| 2139 "+jspb.Message.getField($obj$, $index$)", | |
| 2140 "index", JSFieldIndex(field), | |
| 2141 "obj", obj_reference); | |
| 2142 } else { | |
| 2143 // Converts "NaN" and "Infinity" while preserving null. | |
| 2144 printer->Print( | |
| 2145 "jspb.Message.get$cardinality$FloatingPointField($obj$, $index$)", | |
| 2146 "cardinality", field->is_repeated() ? "Repeated" : "Optional", | |
| 2147 "index", JSFieldIndex(field), | |
| 2148 "obj", obj_reference); | |
| 2149 } | |
| 2150 } else { | |
| 2151 printer->Print("jspb.Message.getField($obj$, $index$)", | |
| 2152 "index", JSFieldIndex(field), | |
| 2153 "obj", obj_reference); | |
| 2154 } | |
| 2155 } | |
| 2156 } | |
| 2157 | |
| 2158 void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, | 1922 void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, |
| 2159 io::Printer* printer, | 1923 io::Printer* printer, |
| 2160 const FieldDescriptor* field) const { | 1924 const FieldDescriptor* field) const { |
| 2161 printer->Print("$fieldname$: ", | 1925 printer->Print("$fieldname$: ", |
| 2162 "fieldname", JSObjectFieldName(options, field)); | 1926 "fieldname", JSObjectFieldName(field)); |
| 2163 | 1927 |
| 2164 if (IsMap(options, field)) { | 1928 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 2165 const FieldDescriptor* value_field = MapFieldValue(field); | |
| 2166 // If the map values are of a message type, we must provide their static | |
| 2167 // toObject() method; otherwise we pass undefined for that argument. | |
| 2168 string value_to_object; | |
| 2169 if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | |
| 2170 value_to_object = | |
| 2171 GetPath(options, value_field->message_type()) + ".toObject"; | |
| 2172 } else { | |
| 2173 value_to_object = "undefined"; | |
| 2174 } | |
| 2175 printer->Print( | |
| 2176 "(f = msg.get$name$()) ? f.toObject(includeInstance, $valuetoobject$) " | |
| 2177 ": []", | |
| 2178 "name", JSGetterName(options, field), "valuetoobject", value_to_object); | |
| 2179 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | |
| 2180 // Message field. | 1929 // Message field. |
| 2181 if (field->is_repeated()) { | 1930 if (field->is_repeated()) { |
| 2182 { | 1931 { |
| 2183 printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n" | 1932 printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n" |
| 2184 " $type$.toObject, includeInstance)", | 1933 " $type$.toObject, includeInstance)", |
| 2185 "getter", JSGetterName(options, field), | 1934 "getter", JSGetterName(field), |
| 2186 "type", SubmessageTypeRef(options, field)); | 1935 "type", SubmessageTypeRef(options, field)); |
| 2187 } | 1936 } |
| 2188 } else { | 1937 } else { |
| 2189 printer->Print("(f = msg.get$getter$()) && " | 1938 printer->Print("(f = msg.get$getter$()) && " |
| 2190 "$type$.toObject(includeInstance, f)", | 1939 "$type$.toObject(includeInstance, f)", |
| 2191 "getter", JSGetterName(options, field), | 1940 "getter", JSGetterName(field), |
| 2192 "type", SubmessageTypeRef(options, field)); | 1941 "type", SubmessageTypeRef(options, field)); |
| 2193 } | 1942 } |
| 2194 } else if (field->type() == FieldDescriptor::TYPE_BYTES) { | |
| 2195 // For bytes fields we want to always return the B64 data. | |
| 2196 printer->Print("msg.get$getter$()", | |
| 2197 "getter", JSGetterName(options, field, BYTES_B64)); | |
| 2198 } else { | 1943 } else { |
| 2199 bool use_default = field->has_default_value(); | 1944 // Simple field (singular or repeated). |
| 2200 | 1945 if ((!HasFieldPresence(field) && !field->is_repeated()) || |
| 2201 if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && | 1946 field->type() == FieldDescriptor::TYPE_BYTES) { |
| 2202 // Repeated fields get initialized to their default in the constructor | 1947 // Delegate to the generated get<field>() method in order not to duplicate |
| 2203 // (why?), so we emit a plain getField() call for them. | 1948 // the proto3-field-default-value or byte-coercion logic here. |
| 2204 !field->is_repeated() && !UseBrokenPresenceSemantics(options, field)) { | 1949 printer->Print("msg.get$getter$()", |
| 2205 // Proto3 puts all defaults (including implicit defaults) in toObject(). | 1950 "getter", JSGetterName(field, BYTES_B64)); |
| 2206 // But for proto2 we leave the existing semantics unchanged: unset fields | 1951 } else { |
| 2207 // without default are unset. | 1952 if (field->has_default_value()) { |
| 2208 use_default = true; | 1953 printer->Print("jspb.Message.getField(msg, $index$) == null ? " |
| 1954 "$defaultValue$ : ", |
| 1955 "index", JSFieldIndex(field), |
| 1956 "defaultValue", JSFieldDefault(field)); |
| 1957 } |
| 1958 if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || |
| 1959 field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { |
| 1960 if (field->is_repeated()) { |
| 1961 printer->Print("jspb.Message.getRepeatedFloatingPointField(" |
| 1962 "msg, $index$)", |
| 1963 "index", JSFieldIndex(field)); |
| 1964 } else if (field->is_optional() && !field->has_default_value()) { |
| 1965 printer->Print("jspb.Message.getOptionalFloatingPointField(" |
| 1966 "msg, $index$)", |
| 1967 "index", JSFieldIndex(field)); |
| 1968 } else { |
| 1969 // Convert "NaN" to NaN. |
| 1970 printer->Print("+jspb.Message.getField(msg, $index$)", |
| 1971 "index", JSFieldIndex(field)); |
| 1972 } |
| 1973 } else { |
| 1974 printer->Print("jspb.Message.getField(msg, $index$)", |
| 1975 "index", JSFieldIndex(field)); |
| 1976 } |
| 2209 } | 1977 } |
| 2210 | |
| 2211 // We don't implement this by calling the accessors, because the semantics | |
| 2212 // of the accessors are changing independently of the toObject() semantics. | |
| 2213 // We are migrating the accessors to return defaults instead of null, but | |
| 2214 // it may take longer to migrate toObject (or we might not want to do it at | |
| 2215 // all). So we want to generate independent code. | |
| 2216 GenerateFieldValueExpression(printer, "msg", field, use_default); | |
| 2217 } | 1978 } |
| 2218 } | 1979 } |
| 2219 | 1980 |
| 2220 void Generator::GenerateClassFromObject(const GeneratorOptions& options, | 1981 void Generator::GenerateClassFromObject(const GeneratorOptions& options, |
| 2221 io::Printer* printer, | 1982 io::Printer* printer, |
| 2222 const Descriptor* desc) const { | 1983 const Descriptor* desc) const { |
| 2223 printer->Print( | 1984 printer->Print( |
| 2224 "if (jspb.Message.GENERATE_FROM_OBJECT) {\n" | 1985 "if (jspb.Message.GENERATE_FROM_OBJECT) {\n" |
| 2225 "/**\n" | 1986 "/**\n" |
| 2226 " * Loads data from an object into a new instance of this proto.\n" | 1987 " * Loads data from an object into a new instance of this proto.\n" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2240 printer->Print( | 2001 printer->Print( |
| 2241 " return msg;\n" | 2002 " return msg;\n" |
| 2242 "};\n" | 2003 "};\n" |
| 2243 "}\n"); | 2004 "}\n"); |
| 2244 } | 2005 } |
| 2245 | 2006 |
| 2246 void Generator::GenerateClassFieldFromObject( | 2007 void Generator::GenerateClassFieldFromObject( |
| 2247 const GeneratorOptions& options, | 2008 const GeneratorOptions& options, |
| 2248 io::Printer* printer, | 2009 io::Printer* printer, |
| 2249 const FieldDescriptor* field) const { | 2010 const FieldDescriptor* field) const { |
| 2250 if (IsMap(options, field)) { | 2011 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 2251 const FieldDescriptor* value_field = MapFieldValue(field); | |
| 2252 if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { | |
| 2253 // Since the map values are of message type, we have to do some extra work | |
| 2254 // to recursively call fromObject() on them before setting the map field. | |
| 2255 printer->Print( | |
| 2256 " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n" | |
| 2257 " msg, $index$, jspb.Map.fromObject(obj.$name$, $fieldclass$, " | |
| 2258 "$fieldclass$.fromObject));\n", | |
| 2259 "name", JSObjectFieldName(options, field), | |
| 2260 "index", JSFieldIndex(field), | |
| 2261 "fieldclass", GetPath(options, value_field->message_type())); | |
| 2262 } else { | |
| 2263 // `msg` is a newly-constructed message object that has not yet built any | |
| 2264 // map containers wrapping underlying arrays, so we can simply directly | |
| 2265 // set the array here without fear of a stale wrapper. | |
| 2266 printer->Print( | |
| 2267 " goog.isDef(obj.$name$) && " | |
| 2268 "jspb.Message.setField(msg, $index$, obj.$name$);\n", | |
| 2269 "name", JSObjectFieldName(options, field), | |
| 2270 "index", JSFieldIndex(field)); | |
| 2271 } | |
| 2272 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | |
| 2273 // Message field (singular or repeated) | 2012 // Message field (singular or repeated) |
| 2274 if (field->is_repeated()) { | 2013 if (field->is_repeated()) { |
| 2275 { | 2014 { |
| 2276 printer->Print( | 2015 printer->Print( |
| 2277 " goog.isDef(obj.$name$) && " | 2016 " goog.isDef(obj.$name$) && " |
| 2278 "jspb.Message.setRepeatedWrapperField(\n" | 2017 "jspb.Message.setRepeatedWrapperField(\n" |
| 2279 " msg, $index$, goog.array.map(obj.$name$, function(i) {\n" | 2018 " msg, $index$, goog.array.map(obj.$name$, function(i) {\n" |
| 2280 " return $fieldclass$.fromObject(i);\n" | 2019 " return $fieldclass$.fromObject(i);\n" |
| 2281 " }));\n", | 2020 " }));\n", |
| 2282 "name", JSObjectFieldName(options, field), | 2021 "name", JSObjectFieldName(field), |
| 2283 "index", JSFieldIndex(field), | 2022 "index", JSFieldIndex(field), |
| 2284 "fieldclass", SubmessageTypeRef(options, field)); | 2023 "fieldclass", SubmessageTypeRef(options, field)); |
| 2285 } | 2024 } |
| 2286 } else { | 2025 } else { |
| 2287 printer->Print( | 2026 printer->Print( |
| 2288 " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n" | 2027 " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n" |
| 2289 " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n", | 2028 " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n", |
| 2290 "name", JSObjectFieldName(options, field), | 2029 "name", JSObjectFieldName(field), |
| 2291 "index", JSFieldIndex(field), | 2030 "index", JSFieldIndex(field), |
| 2292 "fieldclass", SubmessageTypeRef(options, field)); | 2031 "fieldclass", SubmessageTypeRef(options, field)); |
| 2293 } | 2032 } |
| 2294 } else { | 2033 } else { |
| 2295 // Simple (primitive) field. | 2034 // Simple (primitive) field. |
| 2296 printer->Print( | 2035 printer->Print( |
| 2297 " goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, " | 2036 " goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, " |
| 2298 "obj.$name$);\n", | 2037 "obj.$name$);\n", |
| 2299 "name", JSObjectFieldName(options, field), | 2038 "name", JSObjectFieldName(field), |
| 2300 "index", JSFieldIndex(field)); | 2039 "index", JSFieldIndex(field)); |
| 2301 } | 2040 } |
| 2302 } | 2041 } |
| 2303 | 2042 |
| 2043 void Generator::GenerateClassClone(const GeneratorOptions& options, |
| 2044 io::Printer* printer, |
| 2045 const Descriptor* desc) const { |
| 2046 printer->Print( |
| 2047 "/**\n" |
| 2048 " * Creates a deep clone of this proto. No data is shared with the " |
| 2049 "original.\n" |
| 2050 " * @return {!$name$} The clone.\n" |
| 2051 " */\n" |
| 2052 "$name$.prototype.cloneMessage = function() {\n" |
| 2053 " return /** @type {!$name$} */ (jspb.Message.cloneMessage(this));\n" |
| 2054 "};\n\n\n", |
| 2055 "name", GetPath(options, desc)); |
| 2056 } |
| 2057 |
| 2304 void Generator::GenerateClassRegistration(const GeneratorOptions& options, | 2058 void Generator::GenerateClassRegistration(const GeneratorOptions& options, |
| 2305 io::Printer* printer, | 2059 io::Printer* printer, |
| 2306 const Descriptor* desc) const { | 2060 const Descriptor* desc) const { |
| 2307 // Register any extensions defined inside this message type. | 2061 // Register any extensions defined inside this message type. |
| 2308 for (int i = 0; i < desc->extension_count(); i++) { | 2062 for (int i = 0; i < desc->extension_count(); i++) { |
| 2309 const FieldDescriptor* extension = desc->extension(i); | 2063 const FieldDescriptor* extension = desc->extension(i); |
| 2310 if (ShouldGenerateExtension(extension)) { | 2064 if (ShouldGenerateExtension(extension)) { |
| 2311 GenerateExtension(options, printer, extension); | 2065 GenerateExtension(options, printer, extension); |
| 2312 } | 2066 } |
| 2313 } | 2067 } |
| 2314 | 2068 |
| 2315 } | 2069 } |
| 2316 | 2070 |
| 2317 void Generator::GenerateClassFields(const GeneratorOptions& options, | 2071 void Generator::GenerateClassFields(const GeneratorOptions& options, |
| 2318 io::Printer* printer, | 2072 io::Printer* printer, |
| 2319 const Descriptor* desc) const { | 2073 const Descriptor* desc) const { |
| 2320 for (int i = 0; i < desc->field_count(); i++) { | 2074 for (int i = 0; i < desc->field_count(); i++) { |
| 2321 if (!IgnoreField(desc->field(i))) { | 2075 if (!IgnoreField(desc->field(i))) { |
| 2322 GenerateClassField(options, printer, desc->field(i)); | 2076 GenerateClassField(options, printer, desc->field(i)); |
| 2323 } | 2077 } |
| 2324 } | 2078 } |
| 2325 } | 2079 } |
| 2326 | 2080 |
| 2327 void GenerateBytesWrapper(const GeneratorOptions& options, | 2081 void GenerateBytesWrapper(const GeneratorOptions& options, |
| 2328 io::Printer* printer, | 2082 io::Printer* printer, |
| 2329 const FieldDescriptor* field, | 2083 const FieldDescriptor* field, |
| 2330 BytesMode bytes_mode) { | 2084 BytesMode bytes_mode) { |
| 2331 string type = JSFieldTypeAnnotation( | 2085 string type = |
| 2332 options, field, | 2086 JSFieldTypeAnnotation(options, field, |
| 2333 /* is_setter_argument = */ false, | 2087 /* force_optional = */ false, |
| 2334 /* force_present = */ false, | 2088 /* force_present = */ !HasFieldPresence(field), |
| 2335 /* singular_if_not_packed = */ false, bytes_mode); | 2089 /* singular_if_not_packed = */ false, |
| 2090 bytes_mode); |
| 2336 printer->Print( | 2091 printer->Print( |
| 2337 "/**\n" | 2092 "/**\n" |
| 2338 " * $fielddef$\n" | 2093 " * $fielddef$\n" |
| 2339 "$comment$" | 2094 "$comment$" |
| 2340 " * This is a type-conversion wrapper around `get$defname$()`\n" | 2095 " * This is a type-conversion wrapper around `get$defname$()`\n" |
| 2341 " * @return {$type$}\n" | 2096 " * @return {$type$}\n" |
| 2342 " */\n" | 2097 " */\n" |
| 2343 "$class$.prototype.get$name$ = function() {\n" | 2098 "$class$.prototype.get$name$ = function() {\n" |
| 2344 " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n" | 2099 " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n" |
| 2345 " this.get$defname$()));\n" | 2100 " this.get$defname$()));\n" |
| 2346 "};\n" | 2101 "};\n" |
| 2347 "\n" | 2102 "\n" |
| 2348 "\n", | 2103 "\n", |
| 2349 "fielddef", FieldDefinition(options, field), | 2104 "fielddef", FieldDefinition(options, field), |
| 2350 "comment", FieldComments(field, bytes_mode), | 2105 "comment", FieldComments(field, bytes_mode), |
| 2351 "type", type, | 2106 "type", type, |
| 2352 "class", GetPath(options, field->containing_type()), | 2107 "class", GetPath(options, field->containing_type()), |
| 2353 "name", JSGetterName(options, field, bytes_mode), | 2108 "name", JSGetterName(field, bytes_mode), |
| 2354 "list", field->is_repeated() ? "List" : "", | 2109 "list", field->is_repeated() ? "List" : "", |
| 2355 "suffix", JSByteGetterSuffix(bytes_mode), | 2110 "suffix", JSByteGetterSuffix(bytes_mode), |
| 2356 "defname", JSGetterName(options, field, BYTES_DEFAULT)); | 2111 "defname", JSGetterName(field, BYTES_DEFAULT)); |
| 2357 } | 2112 } |
| 2358 | 2113 |
| 2359 | 2114 |
| 2360 void Generator::GenerateClassField(const GeneratorOptions& options, | 2115 void Generator::GenerateClassField(const GeneratorOptions& options, |
| 2361 io::Printer* printer, | 2116 io::Printer* printer, |
| 2362 const FieldDescriptor* field) const { | 2117 const FieldDescriptor* field) const { |
| 2363 if (IsMap(options, field)) { | 2118 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 2364 const FieldDescriptor* key_field = MapFieldKey(field); | |
| 2365 const FieldDescriptor* value_field = MapFieldValue(field); | |
| 2366 // Map field: special handling to instantiate the map object on demand. | |
| 2367 string key_type = | |
| 2368 JSFieldTypeAnnotation( | |
| 2369 options, key_field, | |
| 2370 /* is_setter_argument = */ false, | |
| 2371 /* force_present = */ true, | |
| 2372 /* singular_if_not_packed = */ false); | |
| 2373 string value_type = | |
| 2374 JSFieldTypeAnnotation( | |
| 2375 options, value_field, | |
| 2376 /* is_setter_argument = */ false, | |
| 2377 /* force_present = */ true, | |
| 2378 /* singular_if_not_packed = */ false); | |
| 2379 | |
| 2380 printer->Print( | 2119 printer->Print( |
| 2381 "/**\n" | 2120 "/**\n" |
| 2382 " * $fielddef$\n" | 2121 " * $fielddef$\n" |
| 2383 " * @param {boolean=} opt_noLazyCreate Do not create the map if\n" | |
| 2384 " * empty, instead returning `undefined`\n" | |
| 2385 " * @return {!jspb.Map<$keytype$,$valuetype$>}\n" | |
| 2386 " */\n", | |
| 2387 "fielddef", FieldDefinition(options, field), | |
| 2388 "keytype", key_type, | |
| 2389 "valuetype", value_type); | |
| 2390 printer->Print( | |
| 2391 "$class$.prototype.get$name$ = function(opt_noLazyCreate) {\n" | |
| 2392 " return /** @type {!jspb.Map<$keytype$,$valuetype$>} */ (\n", | |
| 2393 "class", GetPath(options, field->containing_type()), | |
| 2394 "name", JSGetterName(options, field), | |
| 2395 "keytype", key_type, | |
| 2396 "valuetype", value_type); | |
| 2397 printer->Print( | |
| 2398 " jspb.Message.getMapField(this, $index$, opt_noLazyCreate", | |
| 2399 "index", JSFieldIndex(field)); | |
| 2400 | |
| 2401 if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { | |
| 2402 printer->Print(",\n" | |
| 2403 " $messageType$", | |
| 2404 "messageType", GetPath(options, value_field->message_type())); | |
| 2405 } else { | |
| 2406 printer->Print(",\n" | |
| 2407 " null"); | |
| 2408 } | |
| 2409 | |
| 2410 printer->Print( | |
| 2411 "));\n"); | |
| 2412 | |
| 2413 printer->Print( | |
| 2414 "};\n" | |
| 2415 "\n" | |
| 2416 "\n"); | |
| 2417 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | |
| 2418 // Message field: special handling in order to wrap the underlying data | |
| 2419 // array with a message object. | |
| 2420 | |
| 2421 printer->Print( | |
| 2422 "/**\n" | |
| 2423 " * $fielddef$\n" | |
| 2424 "$comment$" | 2122 "$comment$" |
| 2425 " * @return {$type$}\n" | 2123 " * @return {$type$}\n" |
| 2426 " */\n", | 2124 " */\n", |
| 2427 "fielddef", FieldDefinition(options, field), | 2125 "fielddef", FieldDefinition(options, field), |
| 2428 "comment", FieldComments(field, BYTES_DEFAULT), | 2126 "comment", FieldComments(field, BYTES_DEFAULT), |
| 2429 "type", JSFieldTypeAnnotation(options, field, | 2127 "type", JSFieldTypeAnnotation(options, field, |
| 2430 /* is_setter_argument = */ false, | 2128 /* force_optional = */ false, |
| 2431 /* force_present = */ false, | 2129 /* force_present = */ false, |
| 2432 /* singular_if_not_packed = */ false)); | 2130 /* singular_if_not_packed = */ false)); |
| 2433 printer->Print( | 2131 printer->Print( |
| 2434 "$class$.prototype.get$name$ = function() {\n" | 2132 "$class$.prototype.get$name$ = function() {\n" |
| 2435 " return /** @type{$type$} */ (\n" | 2133 " return /** @type{$type$} */ (\n" |
| 2436 " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, " | 2134 " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, " |
| 2437 "$index$$required$));\n" | 2135 "$index$$required$));\n" |
| 2438 "};\n" | 2136 "};\n" |
| 2439 "\n" | 2137 "\n" |
| 2440 "\n", | 2138 "\n", |
| 2441 "class", GetPath(options, field->containing_type()), | 2139 "class", GetPath(options, field->containing_type()), |
| 2442 "name", JSGetterName(options, field), | 2140 "name", JSGetterName(field), |
| 2443 "type", JSFieldTypeAnnotation(options, field, | 2141 "type", JSFieldTypeAnnotation(options, field, |
| 2444 /* is_setter_argument = */ false, | 2142 /* force_optional = */ false, |
| 2445 /* force_present = */ false, | 2143 /* force_present = */ false, |
| 2446 /* singular_if_not_packed = */ false), | 2144 /* singular_if_not_packed = */ false), |
| 2447 "rpt", (field->is_repeated() ? "Repeated" : ""), | 2145 "rpt", (field->is_repeated() ? "Repeated" : ""), |
| 2448 "index", JSFieldIndex(field), | 2146 "index", JSFieldIndex(field), |
| 2449 "wrapperclass", SubmessageTypeRef(options, field), | 2147 "wrapperclass", SubmessageTypeRef(options, field), |
| 2450 "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ? | 2148 "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ? |
| 2451 ", 1" : "")); | 2149 ", 1" : "")); |
| 2452 printer->Print( | 2150 printer->Print( |
| 2453 "/** @param {$optionaltype$} value$returndoc$ */\n" | 2151 "/** @param {$optionaltype$} value $returndoc$ */\n" |
| 2454 "$class$.prototype.set$name$ = function(value) {\n" | 2152 "$class$.prototype.set$name$ = function(value) {\n" |
| 2455 " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(", | 2153 " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(", |
| 2456 "optionaltype", | 2154 "optionaltype", |
| 2457 JSFieldTypeAnnotation(options, field, | 2155 JSFieldTypeAnnotation(options, field, |
| 2458 /* is_setter_argument = */ true, | 2156 /* force_optional = */ true, |
| 2459 /* force_present = */ false, | 2157 /* force_present = */ false, |
| 2460 /* singular_if_not_packed = */ false), | 2158 /* singular_if_not_packed = */ false), |
| 2461 "returndoc", JSReturnDoc(options, field), | 2159 "returndoc", JSReturnDoc(options, field), |
| 2462 "class", GetPath(options, field->containing_type()), | 2160 "class", GetPath(options, field->containing_type()), |
| 2463 "name", JSGetterName(options, field), | 2161 "name", JSGetterName(field), |
| 2464 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), | 2162 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), |
| 2465 "repeatedtag", (field->is_repeated() ? "Repeated" : "")); | 2163 "repeatedtag", (field->is_repeated() ? "Repeated" : "")); |
| 2466 | 2164 |
| 2467 printer->Print( | 2165 printer->Print( |
| 2468 "this, $index$$oneofgroup$, value);$returnvalue$\n" | 2166 "this, $index$$oneofgroup$, value);$returnvalue$\n" |
| 2469 "};\n" | 2167 "};\n" |
| 2470 "\n" | 2168 "\n" |
| 2471 "\n", | 2169 "\n", |
| 2472 "index", JSFieldIndex(field), | 2170 "index", JSFieldIndex(field), |
| 2473 "oneofgroup", (field->containing_oneof() ? | 2171 "oneofgroup", (field->containing_oneof() ? |
| 2474 (", " + JSOneofArray(options, field)) : ""), | 2172 (", " + JSOneofArray(options, field)) : ""), |
| 2475 "returnvalue", JSReturnClause(field)); | 2173 "returnvalue", JSReturnClause(field)); |
| 2476 | 2174 |
| 2477 if (field->is_repeated()) { | 2175 printer->Print( |
| 2478 GenerateRepeatedMessageHelperMethods(options, printer, field); | 2176 "$class$.prototype.clear$name$ = function() {\n" |
| 2479 } | 2177 " this.set$name$($clearedvalue$);$returnvalue$\n" |
| 2178 "};\n" |
| 2179 "\n" |
| 2180 "\n", |
| 2181 "class", GetPath(options, field->containing_type()), |
| 2182 "name", JSGetterName(field), |
| 2183 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), |
| 2184 "returnvalue", JSReturnClause(field)); |
| 2480 | 2185 |
| 2481 } else { | 2186 } else { |
| 2482 bool untyped = | 2187 bool untyped = |
| 2483 false; | 2188 false; |
| 2484 | 2189 |
| 2485 // Simple (primitive) field, either singular or repeated. | 2190 // Simple (primitive) field, either singular or repeated. |
| 2486 | 2191 |
| 2487 // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type; | 2192 // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type; |
| 2488 // at this point we "lie" to non-binary users and tell the the return | 2193 // at this point we "lie" to non-binary users and tell the the return |
| 2489 // type is always base64 string, pending a LSC to migrate to typed getters. | 2194 // type is always base64 string, pending a LSC to migrate to typed getters. |
| 2490 BytesMode bytes_mode = | 2195 BytesMode bytes_mode = |
| 2491 field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ? | 2196 field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ? |
| 2492 BYTES_B64 : BYTES_DEFAULT; | 2197 BYTES_B64 : BYTES_DEFAULT; |
| 2493 string typed_annotation = JSFieldTypeAnnotation( | 2198 string typed_annotation = |
| 2494 options, field, | 2199 JSFieldTypeAnnotation(options, field, |
| 2495 /* is_setter_argument = */ false, | 2200 /* force_optional = */ false, |
| 2496 /* force_present = */ false, | 2201 /* force_present = */ !HasFieldPresence(field), |
| 2497 /* singular_if_not_packed = */ false, | 2202 /* singular_if_not_packed = */ false, |
| 2498 /* bytes_mode = */ bytes_mode); | 2203 /* bytes_mode = */ bytes_mode); |
| 2499 if (untyped) { | 2204 if (untyped) { |
| 2500 printer->Print( | 2205 printer->Print( |
| 2501 "/**\n" | 2206 "/**\n" |
| 2502 " * @return {?} Raw field, untyped.\n" | 2207 " * @return {?} Raw field, untyped.\n" |
| 2503 " */\n"); | 2208 " */\n"); |
| 2504 } else { | 2209 } else { |
| 2505 printer->Print( | 2210 printer->Print( |
| 2506 "/**\n" | 2211 "/**\n" |
| 2507 " * $fielddef$\n" | 2212 " * $fielddef$\n" |
| 2508 "$comment$" | 2213 "$comment$" |
| 2509 " * @return {$type$}\n" | 2214 " * @return {$type$}\n" |
| 2510 " */\n", | 2215 " */\n", |
| 2511 "fielddef", FieldDefinition(options, field), | 2216 "fielddef", FieldDefinition(options, field), |
| 2512 "comment", FieldComments(field, bytes_mode), | 2217 "comment", FieldComments(field, bytes_mode), |
| 2513 "type", typed_annotation); | 2218 "type", typed_annotation); |
| 2514 } | 2219 } |
| 2515 | 2220 |
| 2516 printer->Print( | 2221 printer->Print( |
| 2517 "$class$.prototype.get$name$ = function() {\n", | 2222 "$class$.prototype.get$name$ = function() {\n", |
| 2518 "class", GetPath(options, field->containing_type()), | 2223 "class", GetPath(options, field->containing_type()), |
| 2519 "name", JSGetterName(options, field)); | 2224 "name", JSGetterName(field)); |
| 2520 | 2225 |
| 2521 if (untyped) { | 2226 if (untyped) { |
| 2522 printer->Print( | 2227 printer->Print( |
| 2523 " return "); | 2228 " return "); |
| 2524 } else { | 2229 } else { |
| 2525 printer->Print( | 2230 printer->Print( |
| 2526 " return /** @type {$type$} */ (", | 2231 " return /** @type {$type$} */ (", |
| 2527 "type", typed_annotation); | 2232 "type", typed_annotation); |
| 2528 } | 2233 } |
| 2529 | 2234 |
| 2530 bool use_default = !ReturnsNullWhenUnset(options, field); | 2235 // For proto3 fields without presence, use special getters that will return |
| 2531 | 2236 // defaults when the field is unset, possibly constructing a value if |
| 2532 // Raw fields with no default set should just return undefined. | 2237 // required. |
| 2533 if (untyped && !field->has_default_value()) { | 2238 if (!HasFieldPresence(field) && !field->is_repeated()) { |
| 2534 use_default = false; | 2239 printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)", |
| 2240 "index", JSFieldIndex(field), |
| 2241 "default", Proto3PrimitiveFieldDefault(field)); |
| 2242 } else { |
| 2243 if (field->has_default_value()) { |
| 2244 printer->Print("jspb.Message.getField(this, $index$) == null ? " |
| 2245 "$defaultValue$ : ", |
| 2246 "index", JSFieldIndex(field), |
| 2247 "defaultValue", JSFieldDefault(field)); |
| 2248 } |
| 2249 if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || |
| 2250 field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { |
| 2251 if (field->is_repeated()) { |
| 2252 printer->Print("jspb.Message.getRepeatedFloatingPointField(" |
| 2253 "this, $index$)", |
| 2254 "index", JSFieldIndex(field)); |
| 2255 } else if (field->is_optional() && !field->has_default_value()) { |
| 2256 printer->Print("jspb.Message.getOptionalFloatingPointField(" |
| 2257 "this, $index$)", |
| 2258 "index", JSFieldIndex(field)); |
| 2259 } else { |
| 2260 // Convert "NaN" to NaN. |
| 2261 printer->Print("+jspb.Message.getField(this, $index$)", |
| 2262 "index", JSFieldIndex(field)); |
| 2263 } |
| 2264 } else { |
| 2265 printer->Print("jspb.Message.getField(this, $index$)", |
| 2266 "index", JSFieldIndex(field)); |
| 2267 } |
| 2535 } | 2268 } |
| 2536 | 2269 |
| 2537 // Repeated fields get initialized to their default in the constructor | |
| 2538 // (why?), so we emit a plain getField() call for them. | |
| 2539 if (field->is_repeated()) { | |
| 2540 use_default = false; | |
| 2541 } | |
| 2542 | |
| 2543 GenerateFieldValueExpression(printer, "this", field, use_default); | |
| 2544 | |
| 2545 if (untyped) { | 2270 if (untyped) { |
| 2546 printer->Print( | 2271 printer->Print( |
| 2547 ";\n" | 2272 ";\n" |
| 2548 "};\n" | 2273 "};\n" |
| 2549 "\n" | 2274 "\n" |
| 2550 "\n"); | 2275 "\n"); |
| 2551 } else { | 2276 } else { |
| 2552 printer->Print( | 2277 printer->Print( |
| 2553 ");\n" | 2278 ");\n" |
| 2554 "};\n" | 2279 "};\n" |
| 2555 "\n" | 2280 "\n" |
| 2556 "\n"); | 2281 "\n"); |
| 2557 } | 2282 } |
| 2558 | 2283 |
| 2559 if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) { | 2284 if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) { |
| 2560 GenerateBytesWrapper(options, printer, field, BYTES_B64); | 2285 GenerateBytesWrapper(options, printer, field, BYTES_B64); |
| 2561 GenerateBytesWrapper(options, printer, field, BYTES_U8); | 2286 GenerateBytesWrapper(options, printer, field, BYTES_U8); |
| 2562 } | 2287 } |
| 2563 | 2288 |
| 2564 if (untyped) { | 2289 if (untyped) { |
| 2565 printer->Print( | 2290 printer->Print( |
| 2566 "/**\n" | 2291 "/**\n" |
| 2567 " * @param {*} value$returndoc$\n" | 2292 " * @param {*} value $returndoc$\n" |
| 2568 " */\n", | 2293 " */\n", |
| 2569 "returndoc", JSReturnDoc(options, field)); | 2294 "returndoc", JSReturnDoc(options, field)); |
| 2570 } else { | 2295 } else { |
| 2571 printer->Print( | 2296 printer->Print( |
| 2572 "/** @param {$optionaltype$} value$returndoc$ */\n", "optionaltype", | 2297 "/** @param {$optionaltype$} value $returndoc$ */\n", |
| 2573 JSFieldTypeAnnotation( | 2298 "optionaltype", |
| 2574 options, field, | 2299 JSFieldTypeAnnotation(options, field, |
| 2575 /* is_setter_argument = */ true, | 2300 /* force_optional = */ true, |
| 2576 /* force_present = */ false, | 2301 /* force_present = */ !HasFieldPresence(field), |
| 2577 /* singular_if_not_packed = */ false), | 2302 /* singular_if_not_packed = */ false), |
| 2578 "returndoc", JSReturnDoc(options, field)); | 2303 "returndoc", JSReturnDoc(options, field)); |
| 2579 } | 2304 } |
| 2580 printer->Print( | 2305 printer->Print( |
| 2581 "$class$.prototype.set$name$ = function(value) {\n" | 2306 "$class$.prototype.set$name$ = function(value) {\n" |
| 2582 " jspb.Message.set$oneoftag$Field(this, $index$", | 2307 " jspb.Message.set$oneoftag$Field(this, $index$", |
| 2583 "class", GetPath(options, field->containing_type()), | 2308 "class", GetPath(options, field->containing_type()), |
| 2584 "name", JSGetterName(options, field), | 2309 "name", JSGetterName(field), |
| 2585 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), | 2310 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), |
| 2586 "index", JSFieldIndex(field)); | 2311 "index", JSFieldIndex(field)); |
| 2587 printer->Print( | 2312 printer->Print( |
| 2588 "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n" | 2313 "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n" |
| 2589 "};\n" | 2314 "};\n" |
| 2590 "\n" | 2315 "\n" |
| 2591 "\n", | 2316 "\n", |
| 2592 "type", | 2317 "type", |
| 2593 untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "", | 2318 untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "", |
| 2594 "typeclose", untyped ? ")" : "", | 2319 "typeclose", untyped ? ")" : "", |
| 2595 "oneofgroup", | 2320 "oneofgroup", |
| 2596 (field->containing_oneof() ? (", " + JSOneofArray(options, field)) | 2321 (field->containing_oneof() ? (", " + JSOneofArray(options, field)) |
| 2597 : ""), | 2322 : ""), |
| 2598 "returnvalue", JSReturnClause(field), "rptvalueinit", | 2323 "returnvalue", JSReturnClause(field), "rptvalueinit", |
| 2599 (field->is_repeated() ? " || []" : "")); | 2324 (field->is_repeated() ? " || []" : "")); |
| 2600 | 2325 |
| 2601 if (untyped) { | 2326 if (untyped) { |
| 2602 printer->Print( | 2327 printer->Print( |
| 2603 "/**\n" | 2328 "/**\n" |
| 2604 " * Clears the value.$returndoc$\n" | 2329 " * Clears the value. $returndoc$\n" |
| 2605 " */\n", | 2330 " */\n", |
| 2606 "returndoc", JSReturnDoc(options, field)); | 2331 "returndoc", JSReturnDoc(options, field)); |
| 2607 } | 2332 } |
| 2608 | 2333 |
| 2609 | 2334 if (HasFieldPresence(field)) { |
| 2610 if (field->is_repeated()) { | 2335 printer->Print( |
| 2611 GenerateRepeatedPrimitiveHelperMethods(options, printer, field, untyped); | 2336 "$class$.prototype.clear$name$ = function() {\n" |
| 2337 " jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ", |
| 2338 "class", GetPath(options, field->containing_type()), |
| 2339 "name", JSGetterName(field), |
| 2340 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), |
| 2341 "oneofgroup", (field->containing_oneof() ? |
| 2342 (", " + JSOneofArray(options, field)) : ""), |
| 2343 "index", JSFieldIndex(field)); |
| 2344 printer->Print( |
| 2345 "$clearedvalue$);$returnvalue$\n" |
| 2346 "};\n" |
| 2347 "\n" |
| 2348 "\n", |
| 2349 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), |
| 2350 "returnvalue", JSReturnClause(field)); |
| 2612 } | 2351 } |
| 2613 } | 2352 } |
| 2614 | |
| 2615 // Generate clearFoo() method for map fields, repeated fields, and other | |
| 2616 // fields with presence. | |
| 2617 if (IsMap(options, field)) { | |
| 2618 printer->Print( | |
| 2619 "$class$.prototype.clear$name$ = function() {\n" | |
| 2620 " this.get$name$().clear();$returnvalue$\n" | |
| 2621 "};\n" | |
| 2622 "\n" | |
| 2623 "\n", | |
| 2624 "class", GetPath(options, field->containing_type()), | |
| 2625 "name", JSGetterName(options, field), | |
| 2626 "returnvalue", JSReturnClause(field)); | |
| 2627 } else if (field->is_repeated() || | |
| 2628 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && | |
| 2629 !field->is_required())) { | |
| 2630 // Fields where we can delegate to the regular setter. | |
| 2631 printer->Print( | |
| 2632 "$class$.prototype.clear$name$ = function() {\n" | |
| 2633 " this.set$name$($clearedvalue$);$returnvalue$\n" | |
| 2634 "};\n" | |
| 2635 "\n" | |
| 2636 "\n", | |
| 2637 "class", GetPath(options, field->containing_type()), | |
| 2638 "name", JSGetterName(options, field), | |
| 2639 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), | |
| 2640 "returnvalue", JSReturnClause(field)); | |
| 2641 } else if (HasFieldPresence(options, field)) { | |
| 2642 // Fields where we can't delegate to the regular setter because it doesn't | |
| 2643 // accept "undefined" as an argument. | |
| 2644 printer->Print( | |
| 2645 "$class$.prototype.clear$name$ = function() {\n" | |
| 2646 " jspb.Message.set$maybeoneof$Field(this, " | |
| 2647 "$index$$maybeoneofgroup$, ", | |
| 2648 "class", GetPath(options, field->containing_type()), | |
| 2649 "name", JSGetterName(options, field), | |
| 2650 "maybeoneof", (field->containing_oneof() ? "Oneof" : ""), | |
| 2651 "maybeoneofgroup", (field->containing_oneof() ? | |
| 2652 (", " + JSOneofArray(options, field)) : ""), | |
| 2653 "index", JSFieldIndex(field)); | |
| 2654 printer->Print( | |
| 2655 "$clearedvalue$);$returnvalue$\n" | |
| 2656 "};\n" | |
| 2657 "\n" | |
| 2658 "\n", | |
| 2659 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), | |
| 2660 "returnvalue", JSReturnClause(field)); | |
| 2661 } | |
| 2662 | |
| 2663 if (HasFieldPresence(options, field)) { | |
| 2664 printer->Print( | |
| 2665 "/**\n" | |
| 2666 " * Returns whether this field is set.\n" | |
| 2667 " * @return {!boolean}\n" | |
| 2668 " */\n" | |
| 2669 "$class$.prototype.has$name$ = function() {\n" | |
| 2670 " return jspb.Message.getField(this, $index$) != null;\n" | |
| 2671 "};\n" | |
| 2672 "\n" | |
| 2673 "\n", | |
| 2674 "class", GetPath(options, field->containing_type()), | |
| 2675 "name", JSGetterName(options, field), | |
| 2676 "index", JSFieldIndex(field)); | |
| 2677 } | |
| 2678 } | 2353 } |
| 2679 | 2354 |
| 2680 void Generator::GenerateRepeatedPrimitiveHelperMethods( | |
| 2681 const GeneratorOptions& options, io::Printer* printer, | |
| 2682 const FieldDescriptor* field, bool untyped) const { | |
| 2683 printer->Print( | |
| 2684 "/**\n" | |
| 2685 " * @param {!$optionaltype$} value\n" | |
| 2686 " * @param {number=} opt_index\n" | |
| 2687 " */\n" | |
| 2688 "$class$.prototype.add$name$ = function(value, opt_index) {\n" | |
| 2689 " jspb.Message.addToRepeatedField(this, $index$", | |
| 2690 "class", GetPath(options, field->containing_type()), "name", | |
| 2691 JSGetterName(options, field, BYTES_DEFAULT, | |
| 2692 /* drop_list = */ true), | |
| 2693 "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "index", | |
| 2694 JSFieldIndex(field)); | |
| 2695 printer->Print( | |
| 2696 "$oneofgroup$, $type$value$rptvalueinit$$typeclose$, opt_index);\n" | |
| 2697 "};\n" | |
| 2698 "\n" | |
| 2699 "\n", | |
| 2700 "type", untyped ? "/** @type{string|number|boolean|!Uint8Array} */(" : "", | |
| 2701 "typeclose", untyped ? ")" : "", "oneofgroup", | |
| 2702 (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""), | |
| 2703 "rptvalueinit", ""); | |
| 2704 } | |
| 2705 | |
| 2706 void Generator::GenerateRepeatedMessageHelperMethods( | |
| 2707 const GeneratorOptions& options, io::Printer* printer, | |
| 2708 const FieldDescriptor* field) const { | |
| 2709 printer->Print( | |
| 2710 "/**\n" | |
| 2711 " * @param {!$optionaltype$=} opt_value\n" | |
| 2712 " * @param {number=} opt_index\n" | |
| 2713 " * @return {!$optionaltype$}\n" | |
| 2714 " */\n" | |
| 2715 "$class$.prototype.add$name$ = function(opt_value, opt_index) {\n" | |
| 2716 " return jspb.Message.addTo$repeatedtag$WrapperField(", | |
| 2717 "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "class", | |
| 2718 GetPath(options, field->containing_type()), "name", | |
| 2719 JSGetterName(options, field, BYTES_DEFAULT, | |
| 2720 /* drop_list = */ true), | |
| 2721 "repeatedtag", (field->is_repeated() ? "Repeated" : "")); | |
| 2722 | |
| 2723 printer->Print( | |
| 2724 "this, $index$$oneofgroup$, opt_value, $ctor$, opt_index);\n" | |
| 2725 "};\n" | |
| 2726 "\n" | |
| 2727 "\n", | |
| 2728 "index", JSFieldIndex(field), "oneofgroup", | |
| 2729 (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""), | |
| 2730 "ctor", GetPath(options, field->message_type())); | |
| 2731 } | |
| 2732 | |
| 2733 void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options, | 2355 void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options, |
| 2734 io::Printer* printer, | 2356 io::Printer* printer, |
| 2735 const Descriptor* desc) const { | 2357 const Descriptor* desc) const { |
| 2736 if (IsExtendable(desc)) { | 2358 if (IsExtendable(desc)) { |
| 2737 printer->Print( | 2359 printer->Print( |
| 2738 "\n" | 2360 "\n" |
| 2739 "/**\n" | 2361 "/**\n" |
| 2740 " * The extensions registered with this message class. This is a " | 2362 " * The extensions registered with this message class. This is a " |
| 2741 "map of\n" | 2363 "map of\n" |
| 2742 " * extension field number to fieldInfo object.\n" | 2364 " * extension field number to fieldInfo object.\n" |
| 2743 " *\n" | 2365 " *\n" |
| 2744 " * For example:\n" | 2366 " * For example:\n" |
| 2745 " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, " | 2367 " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, " |
| 2746 "ctor: proto.example.MyMessage} }\n" | 2368 "ctor: proto.example.MyMessage} }\n" |
| 2747 " *\n" | 2369 " *\n" |
| 2748 " * fieldName contains the JsCompiler renamed field name property " | 2370 " * fieldName contains the JsCompiler renamed field name property " |
| 2749 "so that it\n" | 2371 "so that it\n" |
| 2750 " * works in OPTIMIZED mode.\n" | 2372 " * works in OPTIMIZED mode.\n" |
| 2751 " *\n" | 2373 " *\n" |
| 2752 " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n" | 2374 " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n" |
| 2753 " */\n" | 2375 " */\n" |
| 2754 "$class$.extensions = {};\n" | 2376 "$class$.extensions = {};\n" |
| 2755 "\n", | 2377 "\n", |
| 2756 "class", GetPath(options, desc)); | 2378 "class", GetPath(options, desc)); |
| 2757 | |
| 2758 printer->Print( | |
| 2759 "\n" | |
| 2760 "/**\n" | |
| 2761 " * The extensions registered with this message class. This is a " | |
| 2762 "map of\n" | |
| 2763 " * extension field number to fieldInfo object.\n" | |
| 2764 " *\n" | |
| 2765 " * For example:\n" | |
| 2766 " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, " | |
| 2767 "ctor: proto.example.MyMessage} }\n" | |
| 2768 " *\n" | |
| 2769 " * fieldName contains the JsCompiler renamed field name property " | |
| 2770 "so that it\n" | |
| 2771 " * works in OPTIMIZED mode.\n" | |
| 2772 " *\n" | |
| 2773 " * @type {!Object.<number, jspb.ExtensionFieldBinaryInfo>}\n" | |
| 2774 " */\n" | |
| 2775 "$class$.extensionsBinary = {};\n" | |
| 2776 "\n", | |
| 2777 "class", GetPath(options, desc)); | |
| 2778 } | 2379 } |
| 2779 } | 2380 } |
| 2780 | 2381 |
| 2781 | 2382 |
| 2782 void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options, | 2383 void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options, |
| 2783 io::Printer* printer, | 2384 io::Printer* printer, |
| 2784 const Descriptor* desc) const { | 2385 const Descriptor* desc) const { |
| 2785 // TODO(cfallin): Handle lazy decoding when requested by field option and/or | 2386 // TODO(cfallin): Handle lazy decoding when requested by field option and/or |
| 2786 // by default for 'bytes' fields and packed repeated fields. | 2387 // by default for 'bytes' fields and packed repeated fields. |
| 2787 | 2388 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2808 "$class$.deserializeBinaryFromReader = function(msg, reader) {\n" | 2409 "$class$.deserializeBinaryFromReader = function(msg, reader) {\n" |
| 2809 " while (reader.nextField()) {\n" | 2410 " while (reader.nextField()) {\n" |
| 2810 " if (reader.isEndGroup()) {\n" | 2411 " if (reader.isEndGroup()) {\n" |
| 2811 " break;\n" | 2412 " break;\n" |
| 2812 " }\n" | 2413 " }\n" |
| 2813 " var field = reader.getFieldNumber();\n" | 2414 " var field = reader.getFieldNumber();\n" |
| 2814 " switch (field) {\n", | 2415 " switch (field) {\n", |
| 2815 "class", GetPath(options, desc)); | 2416 "class", GetPath(options, desc)); |
| 2816 | 2417 |
| 2817 for (int i = 0; i < desc->field_count(); i++) { | 2418 for (int i = 0; i < desc->field_count(); i++) { |
| 2818 if (!IgnoreField(desc->field(i))) { | 2419 GenerateClassDeserializeBinaryField(options, printer, desc->field(i)); |
| 2819 GenerateClassDeserializeBinaryField(options, printer, desc->field(i)); | |
| 2820 } | |
| 2821 } | 2420 } |
| 2822 | 2421 |
| 2823 printer->Print( | 2422 printer->Print( |
| 2824 " default:\n"); | 2423 " default:\n"); |
| 2825 if (IsExtendable(desc)) { | 2424 if (IsExtendable(desc)) { |
| 2826 printer->Print( | 2425 printer->Print( |
| 2827 " jspb.Message.readBinaryExtension(msg, reader, $extobj$Binary,\n" | 2426 " jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n" |
| 2828 " $class$.prototype.getExtension,\n" | 2427 " $class$.prototype.getExtension,\n" |
| 2829 " $class$.prototype.setExtension);\n" | 2428 " $class$.prototype.setExtension);\n" |
| 2830 " break;\n", | 2429 " break;\n", |
| 2831 "extobj", JSExtensionsObjectName(options, desc->file(), desc), | 2430 "extobj", JSExtensionsObjectName(options, desc->file(), desc), |
| 2832 "class", GetPath(options, desc)); | 2431 "class", GetPath(options, desc)); |
| 2833 } else { | 2432 } else { |
| 2834 printer->Print( | 2433 printer->Print( |
| 2835 " reader.skipField();\n" | 2434 " reader.skipField();\n" |
| 2836 " break;\n"); | 2435 " break;\n"); |
| 2837 } | 2436 } |
| 2838 | 2437 |
| 2839 printer->Print( | 2438 printer->Print( |
| 2840 " }\n" | 2439 " }\n" |
| 2841 " }\n" | 2440 " }\n" |
| 2842 " return msg;\n" | 2441 " return msg;\n" |
| 2843 "};\n" | 2442 "};\n" |
| 2844 "\n" | 2443 "\n" |
| 2845 "\n"); | 2444 "\n"); |
| 2846 } | 2445 } |
| 2847 | 2446 |
| 2848 void Generator::GenerateClassDeserializeBinaryField( | 2447 void Generator::GenerateClassDeserializeBinaryField( |
| 2849 const GeneratorOptions& options, | 2448 const GeneratorOptions& options, |
| 2850 io::Printer* printer, | 2449 io::Printer* printer, |
| 2851 const FieldDescriptor* field) const { | 2450 const FieldDescriptor* field) const { |
| 2852 | 2451 |
| 2853 printer->Print(" case $num$:\n", | 2452 printer->Print(" case $num$:\n", |
| 2854 "num", SimpleItoa(field->number())); | 2453 "num", SimpleItoa(field->number())); |
| 2855 | 2454 |
| 2856 if (IsMap(options, field)) { | 2455 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 2857 const FieldDescriptor* key_field = MapFieldKey(field); | |
| 2858 const FieldDescriptor* value_field = MapFieldValue(field); | |
| 2859 printer->Print( | 2456 printer->Print( |
| 2860 " var value = msg.get$name$();\n" | 2457 " var value = new $fieldclass$;\n" |
| 2861 " reader.readMessage(value, function(message, reader) {\n", | 2458 " reader.read$msgOrGroup$($grpfield$value," |
| 2862 "name", JSGetterName(options, field)); | 2459 "$fieldclass$.deserializeBinaryFromReader);\n", |
| 2460 "fieldclass", SubmessageTypeRef(options, field), |
| 2461 "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ? |
| 2462 "Group" : "Message", |
| 2463 "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ? |
| 2464 (SimpleItoa(field->number()) + ", ") : ""); |
| 2465 } else { |
| 2466 printer->Print( |
| 2467 " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n", |
| 2468 "fieldtype", JSFieldTypeAnnotation(options, field, false, true, |
| 2469 /* singular_if_not_packed = */ true, |
| 2470 BYTES_U8), |
| 2471 "reader", JSBinaryReaderMethodName(field)); |
| 2472 } |
| 2863 | 2473 |
| 2864 printer->Print(" jspb.Map.deserializeBinary(message, reader, " | 2474 if (field->is_repeated() && !field->is_packed()) { |
| 2865 "$keyReaderFn$, $valueReaderFn$", | 2475 // Repeated fields receive a |value| one at at a time; append to array |
| 2866 "keyReaderFn", JSBinaryReaderMethodName(options, key_field), | 2476 // returned by get$name$(). Annoyingly, we have to call 'set' after |
| 2867 "valueReaderFn", JSBinaryReaderMethodName(options, value_field)); | 2477 // changing the array. |
| 2868 | 2478 printer->Print(" msg.get$name$().push(value);\n", "name", |
| 2869 if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { | 2479 JSGetterName(field)); |
| 2870 printer->Print(", $messageType$.deserializeBinaryFromReader", | 2480 printer->Print(" msg.set$name$(msg.get$name$());\n", "name", |
| 2871 "messageType", GetPath(options, value_field->message_type())); | 2481 JSGetterName(field)); |
| 2872 } | |
| 2873 | |
| 2874 printer->Print(");\n"); | |
| 2875 printer->Print(" });\n"); | |
| 2876 } else { | 2482 } else { |
| 2877 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | 2483 // Singular fields, and packed repeated fields, receive a |value| either as |
| 2878 printer->Print( | 2484 // the field's value or as the array of all the field's values; set this as |
| 2879 " var value = new $fieldclass$;\n" | 2485 // the field's value directly. |
| 2880 " reader.read$msgOrGroup$($grpfield$value," | 2486 printer->Print( |
| 2881 "$fieldclass$.deserializeBinaryFromReader);\n", | 2487 " msg.set$name$(value);\n", |
| 2882 "fieldclass", SubmessageTypeRef(options, field), | 2488 "name", JSGetterName(field)); |
| 2883 "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ? | |
| 2884 "Group" : "Message", | |
| 2885 "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ? | |
| 2886 (SimpleItoa(field->number()) + ", ") : ""); | |
| 2887 } else { | |
| 2888 printer->Print( | |
| 2889 " var value = /** @type {$fieldtype$} */ " | |
| 2890 "(reader.read$reader$());\n", | |
| 2891 "fieldtype", JSFieldTypeAnnotation(options, field, false, true, | |
| 2892 /* singular_if_not_packed */ true, | |
| 2893 BYTES_U8), | |
| 2894 "reader", | |
| 2895 JSBinaryReadWriteMethodName(field, /* is_writer = */ false)); | |
| 2896 } | |
| 2897 | |
| 2898 if (field->is_repeated() && !field->is_packed()) { | |
| 2899 printer->Print( | |
| 2900 " msg.add$name$(value);\n", "name", | |
| 2901 JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true)); | |
| 2902 } else { | |
| 2903 // Singular fields, and packed repeated fields, receive a |value| either | |
| 2904 // as the field's value or as the array of all the field's values; set | |
| 2905 // this as the field's value directly. | |
| 2906 printer->Print( | |
| 2907 " msg.set$name$(value);\n", | |
| 2908 "name", JSGetterName(options, field)); | |
| 2909 } | |
| 2910 } | 2489 } |
| 2911 | 2490 |
| 2912 printer->Print(" break;\n"); | 2491 printer->Print(" break;\n"); |
| 2913 } | 2492 } |
| 2914 | 2493 |
| 2915 void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options, | 2494 void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options, |
| 2916 io::Printer* printer, | 2495 io::Printer* printer, |
| 2917 const Descriptor* desc) const { | 2496 const Descriptor* desc) const { |
| 2918 printer->Print( | 2497 printer->Print( |
| 2919 "/**\n" | 2498 "/**\n" |
| 2499 " * Class method variant: serializes the given message to binary data\n" |
| 2500 " * (in protobuf wire format), writing to the given BinaryWriter.\n" |
| 2501 " * @param {!$class$} message\n" |
| 2502 " * @param {!jspb.BinaryWriter} writer\n" |
| 2503 " */\n" |
| 2504 "$class$.serializeBinaryToWriter = function(message, " |
| 2505 "writer) {\n" |
| 2506 " message.serializeBinaryToWriter(writer);\n" |
| 2507 "};\n" |
| 2508 "\n" |
| 2509 "\n" |
| 2510 "/**\n" |
| 2920 " * Serializes the message to binary data (in protobuf wire format).\n" | 2511 " * Serializes the message to binary data (in protobuf wire format).\n" |
| 2921 " * @return {!Uint8Array}\n" | 2512 " * @return {!Uint8Array}\n" |
| 2922 " */\n" | 2513 " */\n" |
| 2923 "$class$.prototype.serializeBinary = function() {\n" | 2514 "$class$.prototype.serializeBinary = function() {\n" |
| 2924 " var writer = new jspb.BinaryWriter();\n" | 2515 " var writer = new jspb.BinaryWriter();\n" |
| 2925 " $class$.serializeBinaryToWriter(this, writer);\n" | 2516 " this.serializeBinaryToWriter(writer);\n" |
| 2926 " return writer.getResultBuffer();\n" | 2517 " return writer.getResultBuffer();\n" |
| 2927 "};\n" | 2518 "};\n" |
| 2928 "\n" | 2519 "\n" |
| 2929 "\n" | 2520 "\n" |
| 2930 "/**\n" | 2521 "/**\n" |
| 2931 " * Serializes the given message to binary data (in protobuf wire\n" | 2522 " * Serializes the message to binary data (in protobuf wire format),\n" |
| 2932 " * format), writing to the given BinaryWriter.\n" | 2523 " * writing to the given BinaryWriter.\n" |
| 2933 " * @param {!$class$} message\n" | |
| 2934 " * @param {!jspb.BinaryWriter} writer\n" | 2524 " * @param {!jspb.BinaryWriter} writer\n" |
| 2935 " */\n" | 2525 " */\n" |
| 2936 "$class$.serializeBinaryToWriter = function(message, " | 2526 "$class$.prototype.serializeBinaryToWriter = function (writer) {\n" |
| 2937 "writer) {\n" | |
| 2938 " var f = undefined;\n", | 2527 " var f = undefined;\n", |
| 2939 "class", GetPath(options, desc)); | 2528 "class", GetPath(options, desc)); |
| 2940 | 2529 |
| 2941 for (int i = 0; i < desc->field_count(); i++) { | 2530 for (int i = 0; i < desc->field_count(); i++) { |
| 2942 if (!IgnoreField(desc->field(i))) { | 2531 GenerateClassSerializeBinaryField(options, printer, desc->field(i)); |
| 2943 GenerateClassSerializeBinaryField(options, printer, desc->field(i)); | |
| 2944 } | |
| 2945 } | 2532 } |
| 2946 | 2533 |
| 2947 if (IsExtendable(desc)) { | 2534 if (IsExtendable(desc)) { |
| 2948 printer->Print( | 2535 printer->Print( |
| 2949 " jspb.Message.serializeBinaryExtensions(message, writer,\n" | 2536 " jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n" |
| 2950 " $extobj$Binary, $class$.prototype.getExtension);\n", | 2537 " $class$.prototype.getExtension);\n", |
| 2951 "extobj", JSExtensionsObjectName(options, desc->file(), desc), | 2538 "extobj", JSExtensionsObjectName(options, desc->file(), desc), |
| 2952 "class", GetPath(options, desc)); | 2539 "class", GetPath(options, desc)); |
| 2953 } | 2540 } |
| 2954 | 2541 |
| 2955 printer->Print( | 2542 printer->Print( |
| 2956 "};\n" | 2543 "};\n" |
| 2957 "\n" | 2544 "\n" |
| 2958 "\n"); | 2545 "\n"); |
| 2959 } | 2546 } |
| 2960 | 2547 |
| 2961 void Generator::GenerateClassSerializeBinaryField( | 2548 void Generator::GenerateClassSerializeBinaryField( |
| 2962 const GeneratorOptions& options, | 2549 const GeneratorOptions& options, |
| 2963 io::Printer* printer, | 2550 io::Printer* printer, |
| 2964 const FieldDescriptor* field) const { | 2551 const FieldDescriptor* field) const { |
| 2965 if (HasFieldPresence(options, field) && | 2552 printer->Print( |
| 2966 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { | 2553 " f = this.get$name$();\n", |
| 2967 string typed_annotation = JSFieldTypeAnnotation( | 2554 "name", JSGetterName(field, BYTES_U8)); |
| 2968 options, field, | |
| 2969 /* is_setter_argument = */ false, | |
| 2970 /* force_present = */ false, | |
| 2971 /* singular_if_not_packed = */ false, | |
| 2972 /* bytes_mode = */ BYTES_DEFAULT); | |
| 2973 printer->Print( | |
| 2974 " f = /** @type {$type$} */ " | |
| 2975 "(jspb.Message.getField(message, $index$));\n", | |
| 2976 "index", JSFieldIndex(field), | |
| 2977 "type", typed_annotation); | |
| 2978 } else { | |
| 2979 printer->Print( | |
| 2980 " f = message.get$name$($nolazy$);\n", | |
| 2981 "name", JSGetterName(options, field, BYTES_U8), | |
| 2982 // No lazy creation for maps containers -- fastpath the empty case. | |
| 2983 "nolazy", IsMap(options, field) ? "true" : ""); | |
| 2984 } | |
| 2985 | 2555 |
| 2986 // Print an `if (condition)` statement that evaluates to true if the field | 2556 if (field->is_repeated()) { |
| 2987 // goes on the wire. | |
| 2988 if (IsMap(options, field)) { | |
| 2989 printer->Print( | |
| 2990 " if (f && f.getLength() > 0) {\n"); | |
| 2991 } else if (field->is_repeated()) { | |
| 2992 printer->Print( | 2557 printer->Print( |
| 2993 " if (f.length > 0) {\n"); | 2558 " if (f.length > 0) {\n"); |
| 2994 } else { | 2559 } else { |
| 2995 if (HasFieldPresence(options, field)) { | 2560 if (HasFieldPresence(field)) { |
| 2996 printer->Print( | 2561 printer->Print( |
| 2997 " if (f != null) {\n"); | 2562 " if (f != null) {\n"); |
| 2998 } else { | 2563 } else { |
| 2999 // No field presence: serialize onto the wire only if value is | 2564 // No field presence: serialize onto the wire only if value is |
| 3000 // non-default. Defaults are documented here: | 2565 // non-default. Defaults are documented here: |
| 3001 // https://goto.google.com/lhdfm | 2566 // https://goto.google.com/lhdfm |
| 3002 switch (field->cpp_type()) { | 2567 switch (field->cpp_type()) { |
| 3003 case FieldDescriptor::CPPTYPE_INT32: | 2568 case FieldDescriptor::CPPTYPE_INT32: |
| 3004 case FieldDescriptor::CPPTYPE_INT64: | 2569 case FieldDescriptor::CPPTYPE_INT64: |
| 3005 case FieldDescriptor::CPPTYPE_UINT32: | 2570 case FieldDescriptor::CPPTYPE_UINT32: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3024 printer->Print( | 2589 printer->Print( |
| 3025 " if (f.length > 0) {\n"); | 2590 " if (f.length > 0) {\n"); |
| 3026 break; | 2591 break; |
| 3027 default: | 2592 default: |
| 3028 assert(false); | 2593 assert(false); |
| 3029 break; | 2594 break; |
| 3030 } | 2595 } |
| 3031 } | 2596 } |
| 3032 } | 2597 } |
| 3033 | 2598 |
| 3034 // Write the field on the wire. | 2599 printer->Print( |
| 3035 if (IsMap(options, field)) { | 2600 " writer.$writer$(\n" |
| 3036 const FieldDescriptor* key_field = MapFieldKey(field); | 2601 " $index$,\n" |
| 3037 const FieldDescriptor* value_field = MapFieldValue(field); | 2602 " f", |
| 2603 "writer", JSBinaryWriterMethodName(field), |
| 2604 "index", SimpleItoa(field->number())); |
| 2605 |
| 2606 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 3038 printer->Print( | 2607 printer->Print( |
| 3039 " f.serializeBinary($index$, writer, " | 2608 ",\n" |
| 3040 "$keyWriterFn$, $valueWriterFn$", | 2609 " $submsg$.serializeBinaryToWriter\n", |
| 3041 "index", SimpleItoa(field->number()), | 2610 "submsg", SubmessageTypeRef(options, field)); |
| 3042 "keyWriterFn", JSBinaryWriterMethodName(options, key_field), | |
| 3043 "valueWriterFn", JSBinaryWriterMethodName(options, value_field)); | |
| 3044 | |
| 3045 if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { | |
| 3046 printer->Print(", $messageType$.serializeBinaryToWriter", | |
| 3047 "messageType", GetPath(options, value_field->message_type())); | |
| 3048 } | |
| 3049 | |
| 3050 printer->Print(");\n"); | |
| 3051 } else { | 2611 } else { |
| 3052 printer->Print( | 2612 printer->Print("\n"); |
| 3053 " writer.write$method$(\n" | |
| 3054 " $index$,\n" | |
| 3055 " f", | |
| 3056 "method", JSBinaryReadWriteMethodName(field, /* is_writer = */ true), | |
| 3057 "index", SimpleItoa(field->number())); | |
| 3058 | |
| 3059 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && | |
| 3060 !IsMap(options, field)) { | |
| 3061 printer->Print( | |
| 3062 ",\n" | |
| 3063 " $submsg$.serializeBinaryToWriter\n", | |
| 3064 "submsg", SubmessageTypeRef(options, field)); | |
| 3065 } else { | |
| 3066 printer->Print("\n"); | |
| 3067 } | |
| 3068 | |
| 3069 printer->Print( | |
| 3070 " );\n"); | |
| 3071 } | 2613 } |
| 3072 | |
| 3073 // Close the `if`. | |
| 3074 printer->Print( | 2614 printer->Print( |
| 2615 " );\n" |
| 3075 " }\n"); | 2616 " }\n"); |
| 3076 } | 2617 } |
| 3077 | 2618 |
| 3078 void Generator::GenerateEnum(const GeneratorOptions& options, | 2619 void Generator::GenerateEnum(const GeneratorOptions& options, |
| 3079 io::Printer* printer, | 2620 io::Printer* printer, |
| 3080 const EnumDescriptor* enumdesc) const { | 2621 const EnumDescriptor* enumdesc) const { |
| 3081 printer->Print( | 2622 printer->Print( |
| 3082 "/**\n" | 2623 "/**\n" |
| 3083 " * @enum {number}\n" | 2624 " * @enum {number}\n" |
| 3084 " */\n" | 2625 " */\n" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3108 GetPath(options, field->file())); | 2649 GetPath(options, field->file())); |
| 3109 | 2650 |
| 3110 printer->Print( | 2651 printer->Print( |
| 3111 "\n" | 2652 "\n" |
| 3112 "/**\n" | 2653 "/**\n" |
| 3113 " * A tuple of {field number, class constructor} for the extension\n" | 2654 " * A tuple of {field number, class constructor} for the extension\n" |
| 3114 " * field named `$name$`.\n" | 2655 " * field named `$name$`.\n" |
| 3115 " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n" | 2656 " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n" |
| 3116 " */\n" | 2657 " */\n" |
| 3117 "$class$.$name$ = new jspb.ExtensionFieldInfo(\n", | 2658 "$class$.$name$ = new jspb.ExtensionFieldInfo(\n", |
| 3118 "name", JSObjectFieldName(options, field), | 2659 "name", JSObjectFieldName(field), |
| 3119 "class", extension_scope, | 2660 "class", extension_scope, |
| 3120 "extensionType", JSFieldTypeAnnotation( | 2661 "extensionType", JSFieldTypeAnnotation( |
| 3121 options, field, | 2662 options, field, |
| 3122 /* is_setter_argument = */ false, | 2663 /* force_optional = */ false, |
| 3123 /* force_present = */ true, | 2664 /* force_present = */ true, |
| 3124 /* singular_if_not_packed = */ false)); | 2665 /* singular_if_not_packed = */ false)); |
| 3125 printer->Print( | 2666 printer->Print( |
| 3126 " $index$,\n" | 2667 " $index$,\n" |
| 3127 " {$name$: 0},\n" | 2668 " {$name$: 0},\n" |
| 3128 " $ctor$,\n" | 2669 " $ctor$,\n" |
| 3129 " /** @type {?function((boolean|undefined),!jspb.Message=): " | 2670 " /** @type {?function((boolean|undefined),!jspb.Message=): " |
| 3130 "!Object} */ (\n" | 2671 "!Object} */ (\n" |
| 3131 " $toObject$),\n" | 2672 " $toObject$),\n" |
| 3132 " $repeated$);\n", | 2673 " $repeated$", |
| 3133 "index", SimpleItoa(field->number()), | 2674 "index", SimpleItoa(field->number()), |
| 3134 "name", JSObjectFieldName(options, field), | 2675 "name", JSObjectFieldName(field), |
| 3135 "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? | 2676 "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? |
| 3136 SubmessageTypeRef(options, field) : string("null")), | 2677 SubmessageTypeRef(options, field) : string("null")), |
| 3137 "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? | 2678 "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? |
| 3138 (SubmessageTypeRef(options, field) + ".toObject") : | 2679 (SubmessageTypeRef(options, field) + ".toObject") : |
| 3139 string("null")), | 2680 string("null")), |
| 3140 "repeated", (field->is_repeated() ? "1" : "0")); | 2681 "repeated", (field->is_repeated() ? "1" : "0")); |
| 3141 | 2682 |
| 3142 printer->Print( | 2683 if (options.binary) { |
| 3143 "\n" | 2684 printer->Print( |
| 3144 "$extendName$Binary[$index$] = new jspb.ExtensionFieldBinaryInfo(\n" | 2685 ",\n" |
| 3145 " $class$.$name$,\n" | 2686 " jspb.BinaryReader.prototype.$binaryReaderFn$,\n" |
| 3146 " $binaryReaderFn$,\n" | 2687 " jspb.BinaryWriter.prototype.$binaryWriterFn$,\n" |
| 3147 " $binaryWriterFn$,\n" | 2688 " $binaryMessageSerializeFn$,\n" |
| 3148 " $binaryMessageSerializeFn$,\n" | 2689 " $binaryMessageDeserializeFn$,\n" |
| 3149 " $binaryMessageDeserializeFn$,\n", | 2690 " $isPacked$);\n", |
| 3150 "extendName", | 2691 "binaryReaderFn", JSBinaryReaderMethodName(field), |
| 3151 JSExtensionsObjectName(options, field->file(), field->containing_type()), | 2692 "binaryWriterFn", JSBinaryWriterMethodName(field), |
| 3152 "index", SimpleItoa(field->number()), "class", extension_scope, "name", | 2693 "binaryMessageSerializeFn", |
| 3153 JSObjectFieldName(options, field), "binaryReaderFn", | 2694 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? |
| 3154 JSBinaryReaderMethodName(options, field), "binaryWriterFn", | 2695 (SubmessageTypeRef(options, field) + |
| 3155 JSBinaryWriterMethodName(options, field), "binaryMessageSerializeFn", | 2696 ".serializeBinaryToWriter") : "null", |
| 3156 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) | 2697 "binaryMessageDeserializeFn", |
| 3157 ? (SubmessageTypeRef(options, field) + ".serializeBinaryToWriter") | 2698 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? |
| 3158 : "undefined", | 2699 (SubmessageTypeRef(options, field) + |
| 3159 "binaryMessageDeserializeFn", | 2700 ".deserializeBinaryFromReader") : "null", |
| 3160 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) | 2701 "isPacked", (field->is_packed() ? "true" : "false")); |
| 3161 ? (SubmessageTypeRef(options, field) + ".deserializeBinaryFromReader") | 2702 } else { |
| 3162 : "undefined"); | 2703 printer->Print(");\n"); |
| 3163 | 2704 } |
| 3164 printer->Print(" $isPacked$);\n", "isPacked", | |
| 3165 (field->is_packed() ? "true" : "false")); | |
| 3166 | 2705 |
| 3167 printer->Print( | 2706 printer->Print( |
| 3168 "// 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" |
| 3169 "// toObject() will function correctly.\n" | 2708 "// toObject() will function correctly.\n" |
| 3170 "$extendName$[$index$] = $class$.$name$;\n" | 2709 "$extendName$[$index$] = $class$.$name$;\n" |
| 3171 "\n", | 2710 "\n", |
| 3172 "extendName", JSExtensionsObjectName(options, field->file(), | 2711 "extendName", JSExtensionsObjectName(options, field->file(), |
| 3173 field->containing_type()), | 2712 field->containing_type()), |
| 3174 "index", SimpleItoa(field->number()), | 2713 "index", SimpleItoa(field->number()), |
| 3175 "class", extension_scope, | 2714 "class", extension_scope, |
| 3176 "name", JSObjectFieldName(options, field)); | 2715 "name", JSObjectFieldName(field)); |
| 3177 } | 2716 } |
| 3178 | 2717 |
| 3179 bool GeneratorOptions::ParseFromOptions( | 2718 bool GeneratorOptions::ParseFromOptions( |
| 3180 const std::vector< std::pair< string, string > >& options, | 2719 const vector< pair< string, string > >& options, |
| 3181 string* error) { | 2720 string* error) { |
| 3182 for (int i = 0; i < options.size(); i++) { | 2721 for (int i = 0; i < options.size(); i++) { |
| 3183 if (options[i].first == "add_require_for_enums") { | 2722 if (options[i].first == "add_require_for_enums") { |
| 3184 if (options[i].second != "") { | 2723 if (options[i].second != "") { |
| 3185 *error = "Unexpected option value for add_require_for_enums"; | 2724 *error = "Unexpected option value for add_require_for_enums"; |
| 3186 return false; | 2725 return false; |
| 3187 } | 2726 } |
| 3188 add_require_for_enums = true; | 2727 add_require_for_enums = true; |
| 3189 } else if (options[i].first == "binary") { | 2728 } else if (options[i].first == "binary") { |
| 3190 if (options[i].second != "") { | 2729 if (options[i].second != "") { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3205 } | 2744 } |
| 3206 error_on_name_conflict = true; | 2745 error_on_name_conflict = true; |
| 3207 } else if (options[i].first == "output_dir") { | 2746 } else if (options[i].first == "output_dir") { |
| 3208 output_dir = options[i].second; | 2747 output_dir = options[i].second; |
| 3209 } else if (options[i].first == "namespace_prefix") { | 2748 } else if (options[i].first == "namespace_prefix") { |
| 3210 namespace_prefix = options[i].second; | 2749 namespace_prefix = options[i].second; |
| 3211 } else if (options[i].first == "library") { | 2750 } else if (options[i].first == "library") { |
| 3212 library = options[i].second; | 2751 library = options[i].second; |
| 3213 } else if (options[i].first == "import_style") { | 2752 } else if (options[i].first == "import_style") { |
| 3214 if (options[i].second == "closure") { | 2753 if (options[i].second == "closure") { |
| 3215 import_style = kImportClosure; | 2754 import_style = IMPORT_CLOSURE; |
| 3216 } else if (options[i].second == "commonjs") { | 2755 } else if (options[i].second == "commonjs") { |
| 3217 import_style = kImportCommonJs; | 2756 import_style = IMPORT_COMMONJS; |
| 3218 } else if (options[i].second == "browser") { | 2757 } else if (options[i].second == "browser") { |
| 3219 import_style = kImportBrowser; | 2758 import_style = IMPORT_BROWSER; |
| 3220 } else if (options[i].second == "es6") { | 2759 } else if (options[i].second == "es6") { |
| 3221 import_style = kImportEs6; | 2760 import_style = IMPORT_ES6; |
| 3222 } else { | 2761 } else { |
| 3223 *error = "Unknown import style " + options[i].second + ", expected " + | 2762 *error = "Unknown import style " + options[i].second + ", expected " + |
| 3224 "one of: closure, commonjs, browser, es6."; | 2763 "one of: closure, commonjs, browser, es6."; |
| 3225 } | 2764 } |
| 3226 } else if (options[i].first == "extension") { | |
| 3227 extension = options[i].second; | |
| 3228 } else if (options[i].first == "one_output_file_per_input_file") { | |
| 3229 if (!options[i].second.empty()) { | |
| 3230 *error = "Unexpected option value for one_output_file_per_input_file"; | |
| 3231 return false; | |
| 3232 } | |
| 3233 one_output_file_per_input_file = true; | |
| 3234 } else { | 2765 } else { |
| 3235 // 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 |
| 3236 // `key` rather than a `key=value` option. | 2767 // `key` rather than a `key=value` option. |
| 3237 if (options[i].second != "") { | 2768 if (options[i].second != "") { |
| 3238 *error = "Unknown option: " + options[i].first; | 2769 *error = "Unknown option: " + options[i].first; |
| 3239 return false; | 2770 return false; |
| 3240 } | 2771 } |
| 3241 output_dir = options[i].first; | 2772 output_dir = options[i].first; |
| 3242 } | 2773 } |
| 3243 } | 2774 } |
| 3244 | 2775 |
| 3245 if (import_style != kImportClosure && | 2776 if (!library.empty() && import_style != IMPORT_CLOSURE) { |
| 3246 (add_require_for_enums || testonly || !library.empty() || | 2777 *error = "The library option should only be used for " |
| 3247 error_on_name_conflict || extension != ".js" || | 2778 "import_style=closure"; |
| 3248 one_output_file_per_input_file)) { | |
| 3249 *error = | |
| 3250 "The add_require_for_enums, testonly, library, error_on_name_conflict, " | |
| 3251 "extension, and one_output_file_per_input_file options should only be " | |
| 3252 "used for import_style=closure"; | |
| 3253 return false; | |
| 3254 } | 2779 } |
| 3255 | 2780 |
| 3256 return true; | 2781 return true; |
| 3257 } | 2782 } |
| 3258 | 2783 |
| 3259 GeneratorOptions::OutputMode GeneratorOptions::output_mode() const { | |
| 3260 // We use one output file per input file if we are not using Closure or if | |
| 3261 // this is explicitly requested. | |
| 3262 if (import_style != kImportClosure || one_output_file_per_input_file) { | |
| 3263 return kOneOutputFilePerInputFile; | |
| 3264 } | |
| 3265 | |
| 3266 // If a library name is provided, we put everything in that one file. | |
| 3267 if (!library.empty()) { | |
| 3268 return kEverythingInOneFile; | |
| 3269 } | |
| 3270 | |
| 3271 // Otherwise, we create one output file per type. | |
| 3272 return kOneOutputFilePerType; | |
| 3273 } | |
| 3274 | |
| 3275 void Generator::GenerateFilesInDepOrder( | 2784 void Generator::GenerateFilesInDepOrder( |
| 3276 const GeneratorOptions& options, | 2785 const GeneratorOptions& options, |
| 3277 io::Printer* printer, | 2786 io::Printer* printer, |
| 3278 const std::vector<const FileDescriptor*>& files) const { | 2787 const vector<const FileDescriptor*>& files) const { |
| 3279 // 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 |
| 3280 // into a dep not specified in the user's command line. | 2789 // into a dep not specified in the user's command line. |
| 3281 std::set<const FileDescriptor*> all_files(files.begin(), files.end()); | 2790 std::set<const FileDescriptor*> all_files(files.begin(), files.end()); |
| 3282 // Track the in-progress set of files that have been generated already. | 2791 // Track the in-progress set of files that have been generated already. |
| 3283 std::set<const FileDescriptor*> generated; | 2792 std::set<const FileDescriptor*> generated; |
| 3284 for (int i = 0; i < files.size(); i++) { | 2793 for (int i = 0; i < files.size(); i++) { |
| 3285 GenerateFileAndDeps(options, printer, files[i], &all_files, &generated); | 2794 GenerateFileAndDeps(options, printer, files[i], &all_files, &generated); |
| 3286 } | 2795 } |
| 3287 } | 2796 } |
| 3288 | 2797 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3311 GenerateClassesAndEnums(options, printer, root); | 2820 GenerateClassesAndEnums(options, printer, root); |
| 3312 } | 2821 } |
| 3313 } | 2822 } |
| 3314 | 2823 |
| 3315 void Generator::GenerateFile(const GeneratorOptions& options, | 2824 void Generator::GenerateFile(const GeneratorOptions& options, |
| 3316 io::Printer* printer, | 2825 io::Printer* printer, |
| 3317 const FileDescriptor* file) const { | 2826 const FileDescriptor* file) const { |
| 3318 GenerateHeader(options, printer); | 2827 GenerateHeader(options, printer); |
| 3319 | 2828 |
| 3320 // Generate "require" statements. | 2829 // Generate "require" statements. |
| 3321 if (options.import_style == GeneratorOptions::kImportCommonJs) { | 2830 if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { |
| 3322 printer->Print("var jspb = require('google-protobuf');\n"); | 2831 printer->Print("var jspb = require('google-protobuf');\n"); |
| 3323 printer->Print("var goog = jspb;\n"); | 2832 printer->Print("var goog = jspb;\n"); |
| 3324 printer->Print("var global = Function('return this')();\n\n"); | 2833 printer->Print("var global = Function('return this')();\n\n"); |
| 3325 | 2834 |
| 3326 for (int i = 0; i < file->dependency_count(); i++) { | 2835 for (int i = 0; i < file->dependency_count(); i++) { |
| 3327 const string& name = file->dependency(i)->name(); | 2836 const string& name = file->dependency(i)->name(); |
| 3328 printer->Print( | 2837 printer->Print( |
| 3329 "var $alias$ = require('$file$');\n", | 2838 "var $alias$ = require('$file$');\n", |
| 3330 "alias", ModuleAlias(name), | 2839 "alias", ModuleAlias(name), |
| 3331 "file", GetRootPath(file->name(), name) + GetJSFilename(options, name)
); | 2840 "file", GetRootPath(file->name()) + GetJSFilename(name)); |
| 3332 } | 2841 } |
| 3333 } | 2842 } |
| 3334 | 2843 |
| 3335 std::set<string> provided; | 2844 // We aren't using Closure's import system, but we use goog.exportSymbol() |
| 3336 std::set<const FieldDescriptor*> extensions; | 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. |
| 3337 for (int i = 0; i < file->extension_count(); i++) { | 2856 for (int i = 0; i < file->extension_count(); i++) { |
| 3338 // We honor the jspb::ignore option here only when working with | 2857 provided.insert(file->extension(i)->full_name()); |
| 3339 // Closure-style imports. Use of this option is discouraged and so we want | |
| 3340 // to avoid adding new support for it. | |
| 3341 if (options.import_style == GeneratorOptions::kImportClosure && | |
| 3342 IgnoreField(file->extension(i))) { | |
| 3343 continue; | |
| 3344 } | |
| 3345 provided.insert(GetPath(options, file) + "." + | |
| 3346 JSObjectFieldName(options, file->extension(i))); | |
| 3347 extensions.insert(file->extension(i)); | |
| 3348 } | 2858 } |
| 3349 | 2859 |
| 3350 FindProvidesForFile(options, printer, file, &provided); | 2860 FindProvidesForFile(options, printer, file, &provided); |
| 3351 GenerateProvides(options, printer, &provided); | 2861 for (std::set<string>::iterator it = provided.begin(); |
| 3352 std::vector<const FileDescriptor*> files; | 2862 it != provided.end(); ++it) { |
| 3353 files.push_back(file); | 2863 printer->Print("goog.exportSymbol('$name$', null, global);\n", |
| 3354 if (options.import_style == GeneratorOptions::kImportClosure) { | 2864 "name", *it); |
| 3355 GenerateRequiresForLibrary(options, printer, files, &provided); | |
| 3356 } | 2865 } |
| 3357 | 2866 |
| 3358 GenerateClassesAndEnums(options, printer, file); | 2867 GenerateClassesAndEnums(options, printer, file); |
| 3359 | 2868 |
| 3360 // Generate code for top-level extensions. Extensions nested inside messages | 2869 // Extensions nested inside messages are emitted inside |
| 3361 // are emitted inside GenerateClassesAndEnums(). | 2870 // GenerateClassesAndEnums(). |
| 3362 for (std::set<const FieldDescriptor*>::const_iterator it = extensions.begin(); | 2871 for (int i = 0; i < file->extension_count(); i++) { |
| 3363 it != extensions.end(); ++it) { | 2872 GenerateExtension(options, printer, file->extension(i)); |
| 3364 GenerateExtension(options, printer, *it); | |
| 3365 } | 2873 } |
| 3366 | 2874 |
| 3367 if (options.import_style == GeneratorOptions::kImportCommonJs) { | 2875 if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { |
| 3368 printer->Print("goog.object.extend(exports, $package$);\n", | 2876 printer->Print("goog.object.extend(exports, $package$);\n", |
| 3369 "package", GetPath(options, file)); | 2877 "package", GetPath(options, file)); |
| 3370 } | 2878 } |
| 3371 | |
| 3372 // Emit well-known type methods. | |
| 3373 for (FileToc* toc = well_known_types_js; toc->name != NULL; toc++) { | |
| 3374 string name = string("google/protobuf/") + toc->name; | |
| 3375 if (name == StripProto(file->name()) + ".js") { | |
| 3376 printer->Print(toc->data); | |
| 3377 } | |
| 3378 } | |
| 3379 } | 2879 } |
| 3380 | 2880 |
| 3381 bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files, | 2881 bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, |
| 3382 const string& parameter, | 2882 const string& parameter, |
| 3383 GeneratorContext* context, | 2883 GeneratorContext* context, |
| 3384 string* error) const { | 2884 string* error) const { |
| 3385 std::vector< std::pair< string, string > > option_pairs; | 2885 vector< pair< string, string > > option_pairs; |
| 3386 ParseGeneratorParameter(parameter, &option_pairs); | 2886 ParseGeneratorParameter(parameter, &option_pairs); |
| 3387 GeneratorOptions options; | 2887 GeneratorOptions options; |
| 3388 if (!options.ParseFromOptions(option_pairs, error)) { | 2888 if (!options.ParseFromOptions(option_pairs, error)) { |
| 3389 return false; | 2889 return false; |
| 3390 } | 2890 } |
| 3391 | 2891 |
| 3392 | 2892 |
| 3393 if (options.output_mode() == GeneratorOptions::kEverythingInOneFile) { | 2893 // There are three schemes for where output files go: |
| 2894 // |
| 2895 // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file |
| 2896 // - import_style = IMPORT_CLOSURE, library empty: one output file per type |
| 2897 // - import_style != IMPORT_CLOSURE: one output file per .proto file |
| 2898 if (options.import_style == GeneratorOptions::IMPORT_CLOSURE && |
| 2899 options.library != "") { |
| 3394 // All output should go in a single file. | 2900 // All output should go in a single file. |
| 3395 string filename = options.output_dir + "/" + options.library + | 2901 string filename = options.output_dir + "/" + options.library + ".js"; |
| 3396 options.GetFileNameExtension(); | |
| 3397 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(
filename)); | 2902 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(
filename)); |
| 3398 GOOGLE_CHECK(output.get()); | 2903 GOOGLE_CHECK(output.get()); |
| 3399 io::Printer printer(output.get(), '$'); | 2904 io::Printer printer(output.get(), '$'); |
| 3400 | 2905 |
| 3401 // Pull out all extensions -- we need these to generate all | 2906 // Pull out all extensions -- we need these to generate all |
| 3402 // provides/requires. | 2907 // provides/requires. |
| 3403 std::vector<const FieldDescriptor*> extensions; | 2908 vector<const FieldDescriptor*> extensions; |
| 3404 for (int i = 0; i < files.size(); i++) { | 2909 for (int i = 0; i < files.size(); i++) { |
| 3405 for (int j = 0; j < files[i]->extension_count(); j++) { | 2910 for (int j = 0; j < files[i]->extension_count(); j++) { |
| 3406 const FieldDescriptor* extension = files[i]->extension(j); | 2911 const FieldDescriptor* extension = files[i]->extension(j); |
| 3407 extensions.push_back(extension); | 2912 extensions.push_back(extension); |
| 3408 } | 2913 } |
| 3409 } | 2914 } |
| 3410 | 2915 |
| 3411 GenerateHeader(options, &printer); | 2916 GenerateHeader(options, &printer); |
| 3412 | 2917 |
| 3413 std::set<string> provided; | 2918 std::set<string> provided; |
| 3414 FindProvides(options, &printer, files, &provided); | 2919 FindProvides(options, &printer, files, &provided); |
| 3415 FindProvidesForFields(options, &printer, extensions, &provided); | 2920 FindProvidesForFields(options, &printer, extensions, &provided); |
| 3416 GenerateProvides(options, &printer, &provided); | 2921 GenerateProvides(options, &printer, &provided); |
| 3417 GenerateTestOnly(options, &printer); | 2922 GenerateTestOnly(options, &printer); |
| 3418 GenerateRequiresForLibrary(options, &printer, files, &provided); | 2923 GenerateRequiresForLibrary(options, &printer, files, &provided); |
| 3419 | 2924 |
| 3420 GenerateFilesInDepOrder(options, &printer, files); | 2925 GenerateFilesInDepOrder(options, &printer, files); |
| 3421 | 2926 |
| 3422 for (int i = 0; i < extensions.size(); i++) { | 2927 for (int i = 0; i < extensions.size(); i++) { |
| 3423 if (ShouldGenerateExtension(extensions[i])) { | 2928 if (ShouldGenerateExtension(extensions[i])) { |
| 3424 GenerateExtension(options, &printer, extensions[i]); | 2929 GenerateExtension(options, &printer, extensions[i]); |
| 3425 } | 2930 } |
| 3426 } | 2931 } |
| 3427 | 2932 |
| 3428 if (printer.failed()) { | 2933 if (printer.failed()) { |
| 3429 return false; | 2934 return false; |
| 3430 } | 2935 } |
| 3431 } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerType) { | 2936 } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { |
| 3432 std::set<const void*> allowed_set; | 2937 set<const void*> allowed_set; |
| 3433 if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) { | 2938 if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) { |
| 3434 return false; | 2939 return false; |
| 3435 } | 2940 } |
| 3436 | 2941 |
| 3437 for (int i = 0; i < files.size(); i++) { | 2942 for (int i = 0; i < files.size(); i++) { |
| 3438 const FileDescriptor* file = files[i]; | 2943 const FileDescriptor* file = files[i]; |
| 3439 for (int j = 0; j < file->message_type_count(); j++) { | 2944 for (int j = 0; j < file->message_type_count(); j++) { |
| 3440 const Descriptor* desc = file->message_type(j); | 2945 const Descriptor* desc = file->message_type(j); |
| 3441 if (allowed_set.count(desc) == 0) { | 2946 if (allowed_set.count(desc) == 0) { |
| 3442 continue; | 2947 continue; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3493 string filename = GetExtensionFileName(options, file); | 2998 string filename = GetExtensionFileName(options, file); |
| 3494 | 2999 |
| 3495 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( | 3000 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( |
| 3496 context->Open(filename)); | 3001 context->Open(filename)); |
| 3497 GOOGLE_CHECK(output.get()); | 3002 GOOGLE_CHECK(output.get()); |
| 3498 io::Printer printer(output.get(), '$'); | 3003 io::Printer printer(output.get(), '$'); |
| 3499 | 3004 |
| 3500 GenerateHeader(options, &printer); | 3005 GenerateHeader(options, &printer); |
| 3501 | 3006 |
| 3502 std::set<string> provided; | 3007 std::set<string> provided; |
| 3503 std::vector<const FieldDescriptor*> fields; | 3008 vector<const FieldDescriptor*> fields; |
| 3504 | 3009 |
| 3505 for (int j = 0; j < files[i]->extension_count(); j++) { | 3010 for (int j = 0; j < files[i]->extension_count(); j++) { |
| 3506 if (ShouldGenerateExtension(files[i]->extension(j))) { | 3011 if (ShouldGenerateExtension(files[i]->extension(j))) { |
| 3507 fields.push_back(files[i]->extension(j)); | 3012 fields.push_back(files[i]->extension(j)); |
| 3508 } | 3013 } |
| 3509 } | 3014 } |
| 3510 | 3015 |
| 3511 FindProvidesForFields(options, &printer, fields, &provided); | 3016 FindProvidesForFields(options, &printer, fields, &provided); |
| 3512 GenerateProvides(options, &printer, &provided); | 3017 GenerateProvides(options, &printer, &provided); |
| 3513 GenerateTestOnly(options, &printer); | 3018 GenerateTestOnly(options, &printer); |
| 3514 GenerateRequiresForExtensions(options, &printer, fields, &provided); | 3019 GenerateRequiresForExtensions(options, &printer, fields, &provided); |
| 3515 | 3020 |
| 3516 for (int j = 0; j < files[i]->extension_count(); j++) { | 3021 for (int j = 0; j < files[i]->extension_count(); j++) { |
| 3517 if (ShouldGenerateExtension(files[i]->extension(j))) { | 3022 if (ShouldGenerateExtension(files[i]->extension(j))) { |
| 3518 GenerateExtension(options, &printer, files[i]->extension(j)); | 3023 GenerateExtension(options, &printer, files[i]->extension(j)); |
| 3519 } | 3024 } |
| 3520 } | 3025 } |
| 3521 } | 3026 } |
| 3522 } | 3027 } |
| 3523 } else /* options.output_mode() == kOneOutputFilePerInputFile */ { | 3028 } else { |
| 3524 // Generate one output file per input (.proto) file. | 3029 // Generate one output file per input (.proto) file. |
| 3525 | 3030 |
| 3526 for (int i = 0; i < files.size(); i++) { | 3031 for (int i = 0; i < files.size(); i++) { |
| 3527 const google::protobuf::FileDescriptor* file = files[i]; | 3032 const google::protobuf::FileDescriptor* file = files[i]; |
| 3528 | 3033 |
| 3529 string filename = | 3034 string filename = options.output_dir + "/" + GetJSFilename(file->name()); |
| 3530 options.output_dir + "/" + GetJSFilename(options, file->name()); | |
| 3531 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Ope
n(filename)); | 3035 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Ope
n(filename)); |
| 3532 GOOGLE_CHECK(output.get()); | 3036 GOOGLE_CHECK(output.get()); |
| 3533 io::Printer printer(output.get(), '$'); | 3037 io::Printer printer(output.get(), '$'); |
| 3534 | 3038 |
| 3535 GenerateFile(options, &printer, file); | 3039 GenerateFile(options, &printer, file); |
| 3536 | 3040 |
| 3537 if (printer.failed()) { | 3041 if (printer.failed()) { |
| 3538 return false; | 3042 return false; |
| 3539 } | 3043 } |
| 3540 } | 3044 } |
| 3541 } | 3045 } |
| 3542 | 3046 |
| 3543 return true; | 3047 return true; |
| 3544 } | 3048 } |
| 3545 | 3049 |
| 3546 } // namespace js | 3050 } // namespace js |
| 3547 } // namespace compiler | 3051 } // namespace compiler |
| 3548 } // namespace protobuf | 3052 } // namespace protobuf |
| 3549 } // namespace google | 3053 } // namespace google |
| OLD | NEW |