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