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