protobuf-closure-library 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/
5
+ tmp/
6
+ lib/protoc_js_core.*
7
+ *.pb.cc
8
+ *.pb.h
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in protobuf-closure-library.gemspec
4
+ gemspec
@@ -0,0 +1,31 @@
1
+ Protocol buffer javascript compiler for closure library
2
+ -------------------------------------------------------
3
+
4
+ This gem is a wrapper for native protocol buffer javascript compiler which generates closure library proto2 messages.
5
+
6
+ At the time of writing this gem, google does not provide an official protocol buffer compiler for closure library. An almost identical open source alternative is `protobuf-plugin-closure <http://code.google.com/p/protobuf-plugin-closure/>`_ which this gem is based on.
7
+
8
+ Installation
9
+ ++++++++++++
10
+
11
+ `Protobuf <http://code.google.com/p/protobuf/>`_ runtime compiler and development header and libraries must be present at gem installation time.
12
+
13
+ * Under linux, user the right development package, eg ``libprotobuf-dev`` for ubuntu.
14
+ * Under osx, use ``brew install protobuf``.
15
+ * under windows, use the `official protobuf binaries <http://code.google.com/p/protobuf/downloads/list>`_.
16
+
17
+ Then, install the gem:
18
+
19
+ ::
20
+
21
+ gem install protobuf-closure-library
22
+
23
+ Usage
24
+ +++++
25
+
26
+ ::
27
+
28
+ ProtobufClosureLibrary::ProtocJs.compile input_proto_file,
29
+ output_dir, optional_protoc_arg, ...
30
+
31
+ This generated a ``.pb.js`` file correponded to ``input_proto_file`` in ``output_dir``. The output file contains a subclass of `goog.proto2.Message <http://closure-library.googlecode.com/svn/docs/class_goog_proto2_Message.html>`_.
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ require 'bundler/gem_tasks'
9
+ require 'rake/extensiontask'
10
+ require 'rake/testtask'
11
+
12
+ def gemspec
13
+ @gemspec ||= eval(File.read File.expand_path('../protobuf-closure-library.gemspec', __FILE__))
14
+ end
15
+
16
+ Rake::ExtensionTask.new :protoc_js_core, gemspec
17
+
18
+ Rake::TestTask.new :test do |t|
19
+ t.libs << 'lib'
20
+ t.libs << 'test'
21
+ t.pattern = 'test/**/*_test.rb'
22
+ t.verbose = true
23
+ end
@@ -0,0 +1,732 @@
1
+ // Copyright (c) 2010-2011 SameGoal LLC.
2
+ // All Rights Reserved.
3
+ // Author: Andy Hochhaus <ahochhaus@samegoal.com>
4
+
5
+ // Licensed under the Apache License, Version 2.0 (the "License");
6
+ // you may not use this file except in compliance with the License.
7
+ // You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing, software
12
+ // distributed under the License is distributed on an "AS IS" BASIS,
13
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ // See the License for the specific language governing permissions and
15
+ // limitations under the License.
16
+
17
+ #include "code_generator.h"
18
+
19
+ #include <string>
20
+ #include <iostream> // NOLINT
21
+ #include <sstream> // NOLINT
22
+
23
+ #include "google/protobuf/descriptor.h"
24
+ #include "google/protobuf/io/printer.h"
25
+ #include "google/protobuf/io/zero_copy_stream.h"
26
+ #include "google/protobuf/stubs/common.h"
27
+
28
+ #include "int64_encoding.pb.h"
29
+ #include "javascript_package.pb.h"
30
+
31
+ namespace sg {
32
+ namespace protobuf {
33
+ namespace js {
34
+
35
+ CodeGenerator::CodeGenerator(const std::string &name)
36
+ : name_(name) {}
37
+
38
+ CodeGenerator::~CodeGenerator() {}
39
+
40
+ bool CodeGenerator::Generate(
41
+ const google::protobuf::FileDescriptor *file,
42
+ const std::string &/* parameter */,
43
+ google::protobuf::compiler::OutputDirectory *output_directory,
44
+ std::string *error) const {
45
+
46
+ const std::string file_name = file->name();
47
+ std::string output_file_name = file->name();
48
+ std::size_t loc = output_file_name.rfind(".");
49
+ output_file_name.erase(loc, output_file_name.length() - loc);
50
+ output_file_name.append(".pb.js");
51
+
52
+ google::protobuf::internal::scoped_ptr<
53
+ google::protobuf::io::ZeroCopyOutputStream> output(
54
+ output_directory->Open(output_file_name));
55
+ google::protobuf::io::Printer printer(output.get(), '$');
56
+ printer.Print(
57
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
58
+ printer.Print("// source: $file_name$\n", "file_name", file_name);
59
+ printer.Print("\n");
60
+ printer.Print(
61
+ "/**\n"
62
+ " * @fileoverview Generated Protocol Buffer code for file $file_name$.\n"
63
+ " */\n", "file_name", file_name);
64
+ printer.Print("\n");
65
+
66
+ // goog.provide all messages and enums
67
+ for (int i = 0; i < file->message_type_count(); ++i) {
68
+ CodeGenerator::GenDescriptorGoogProvides(
69
+ file->message_type(i),
70
+ &printer);
71
+ }
72
+ for (int i = 0; i < file->enum_type_count(); ++i) {
73
+ CodeGenerator::GenEnumDescriptorGoogProvides(
74
+ file->enum_type(i),
75
+ &printer);
76
+ }
77
+
78
+ printer.Print("\n");
79
+ printer.Print("goog.require('goog.proto2.Message');\n"
80
+ "\n");
81
+ for (int i = 0; i < file->dependency_count(); ++i) {
82
+ for (int j = 0; j < file->dependency(i)->message_type_count(); j++) {
83
+ printer.Print(
84
+ "goog.require('$file$');\n",
85
+ "file",
86
+ JsFullName(file->dependency(i)->message_type(j)->file(),
87
+ file->dependency(i)->message_type(j)->full_name()));
88
+ }
89
+ }
90
+
91
+ printer.Print("\n");
92
+
93
+ // generate accessor functions
94
+ for (int i = 0; i < file->message_type_count(); ++i) {
95
+ CodeGenerator::GenDescriptor(
96
+ file->message_type(i),
97
+ &printer);
98
+ }
99
+ for (int i = 0; i < file->enum_type_count(); ++i) {
100
+ CodeGenerator::GenEnumDescriptor(
101
+ file->enum_type(i),
102
+ &printer);
103
+ }
104
+
105
+ printer.Print("\n");
106
+
107
+ // generate metadata
108
+ for (int i = 0; i < file->message_type_count(); ++i) {
109
+ CodeGenerator::GenDescriptorMetadata(
110
+ file->message_type(i),
111
+ &printer);
112
+ }
113
+
114
+ if (printer.failed()) {
115
+ *error = "CodeGenerator detected write error.";
116
+ return false;
117
+ }
118
+
119
+ return true;
120
+ }
121
+
122
+ std::string CodeGenerator::JsFullName(
123
+ const google::protobuf::FileDescriptor *file,
124
+ const std::string &full_name) {
125
+ std::string new_name = full_name;
126
+ const std::string package = file->package();
127
+
128
+ std::string prefix = file->options().GetExtension(javascript_package);
129
+ if (prefix.length() > 0) {
130
+ if (package.length() > 0) {
131
+ new_name.erase(0, package.length() + 1);
132
+ }
133
+ new_name = prefix + "." + new_name;
134
+ }
135
+ return new_name;
136
+ }
137
+
138
+ void CodeGenerator::GenDescriptorGoogProvides(
139
+ const google::protobuf::Descriptor *message,
140
+ google::protobuf::io::Printer *printer) {
141
+ printer->Print("goog.provide('$name$');\n",
142
+ "name", JsFullName(message->file(),
143
+ message->full_name()));
144
+
145
+ // enums
146
+ for (int i = 0; i < message->enum_type_count(); ++i) {
147
+ CodeGenerator::GenEnumDescriptorGoogProvides(
148
+ message->enum_type(i),
149
+ printer);
150
+ }
151
+
152
+ // Recursively process nested messages
153
+ for (int i = 0; i < message->nested_type_count(); ++i) {
154
+ CodeGenerator::GenDescriptorGoogProvides(
155
+ message->nested_type(i),
156
+ printer);
157
+ }
158
+ }
159
+
160
+ void CodeGenerator::GenEnumDescriptorGoogProvides(
161
+ const google::protobuf::EnumDescriptor *enum_desc,
162
+ google::protobuf::io::Printer *printer) {
163
+ printer->Print("goog.provide('$name$');\n",
164
+ "name", JsFullName(enum_desc->file(),
165
+ enum_desc->full_name()));
166
+ }
167
+
168
+ void CodeGenerator::GenDescriptor(
169
+ const google::protobuf::Descriptor *message,
170
+ google::protobuf::io::Printer *printer) {
171
+ printer->Print("\n"
172
+ "/**\n"
173
+ " * Message $name$.\n"
174
+ " * @constructor\n"
175
+ " * @extends {goog.proto2.Message}\n"
176
+ " */\n",
177
+ "name", message->name());
178
+ printer->Print("$name$ = function() {\n",
179
+ "name", JsFullName(message->file(),
180
+ message->full_name()));
181
+ printer->Indent();
182
+ printer->Print("goog.proto2.Message.apply(this);\n");
183
+ printer->Outdent();
184
+ printer->Print("};\n"
185
+ "goog.inherits($name$, goog.proto2.Message);\n"
186
+ "\n"
187
+ "\n",
188
+ "name", JsFullName(message->file(),
189
+ message->full_name()));
190
+
191
+ printer->Print(
192
+ "/**\n"
193
+ " * Overrides {@link goog.proto2.Message#clone} to specify its exact "
194
+ "return type.\n"
195
+ " * @return {!$name$} The cloned message.\n"
196
+ " * @override\n"
197
+ " */\n"
198
+ "$name$.prototype.clone;\n",
199
+ "name", JsFullName(message->file(),
200
+ message->full_name()));
201
+
202
+ // fields
203
+ for (int i = 0; i < message->field_count(); ++i) {
204
+ CodeGenerator::GenFieldDescriptor(
205
+ message->field(i),
206
+ printer);
207
+ }
208
+
209
+ // enums
210
+ for (int i = 0; i < message->enum_type_count(); ++i) {
211
+ CodeGenerator::GenEnumDescriptor(
212
+ message->enum_type(i),
213
+ printer);
214
+ }
215
+
216
+ // nested messages (recursively process)
217
+ for (int i = 0; i < message->nested_type_count(); ++i) {
218
+ CodeGenerator::GenDescriptor(
219
+ message->nested_type(i),
220
+ printer);
221
+ printer->Print("\n"
222
+ "\n");
223
+ }
224
+ }
225
+
226
+ void CodeGenerator::GenFieldDescriptor(
227
+ const google::protobuf::FieldDescriptor *field,
228
+ google::protobuf::io::Printer *printer) {
229
+ printer->Print("\n");
230
+ std::string type;
231
+ bool type_is_primitive = false;
232
+ bool as_number = field->options().GetExtension(jstype);
233
+ if (field->type() == google::protobuf::FieldDescriptor::TYPE_BOOL) {
234
+ type = "boolean";
235
+ type_is_primitive = true;
236
+ } else if (
237
+ field->type() == google::protobuf::FieldDescriptor::TYPE_BYTES ||
238
+ field->type() == google::protobuf::FieldDescriptor::TYPE_STRING ||
239
+ ((field->type() == google::protobuf::FieldDescriptor::TYPE_INT64 ||
240
+ field->type() == google::protobuf::FieldDescriptor::TYPE_UINT64 ||
241
+ field->type() == google::protobuf::FieldDescriptor::TYPE_SINT64 ||
242
+ field->type() == google::protobuf::FieldDescriptor::TYPE_FIXED64 ||
243
+ field->type() == google::protobuf::FieldDescriptor::TYPE_SFIXED64) &&
244
+ !as_number)) {
245
+ type = "string";
246
+ type_is_primitive = true;
247
+ } else if (
248
+ field->type() == google::protobuf::FieldDescriptor::TYPE_GROUP ||
249
+ field->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE) {
250
+ type = JsFullName(field->message_type()->file(),
251
+ field->message_type()->full_name());
252
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_ENUM) {
253
+ type = JsFullName(field->enum_type()->file(),
254
+ field->enum_type()->full_name());
255
+ type_is_primitive = true;
256
+ } else {
257
+ type = "number";
258
+ type_is_primitive = true;
259
+ }
260
+
261
+ std::ostringstream number;
262
+ number << field->number();
263
+
264
+ std::string upper_name = field->camelcase_name();
265
+ if (upper_name[0] >= 97 && upper_name[0] <= 122) {
266
+ upper_name[0] -= 32;
267
+ }
268
+
269
+ // get
270
+ if (field->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) {
271
+ printer->Print(
272
+ "\n"
273
+ "/**\n"
274
+ " * Gets the value of the $name$ field at the index given.\n"
275
+ " * @param {number} index The index to lookup.\n",
276
+ "name", field->name());
277
+ printer->Print(
278
+ " * @return {$opt$$type$} The value.\n"
279
+ " */\n",
280
+ "opt", type_is_primitive ? "?" : "",
281
+ "type", type);
282
+ printer->Print(
283
+ "$prefix$.prototype.get$field$ = function(index) {\n",
284
+ "prefix", JsFullName(field->containing_type()->file(),
285
+ field->containing_type()->full_name()),
286
+ "field", upper_name);
287
+ printer->Indent();
288
+ printer->Print(
289
+ "return /** @type {$opt$$type$} */ ",
290
+ "opt", type_is_primitive ? "?" : "",
291
+ "type", type);
292
+ printer->Print(
293
+ "(this.get$$Value($number$, index));\n",
294
+ "number", number.str());
295
+ printer->Outdent();
296
+ printer->Print(
297
+ "};\n"
298
+ "\n");
299
+
300
+ printer->Print(
301
+ "\n"
302
+ "/**\n"
303
+ " * Gets the value of the $name$ field at the index given or the "
304
+ "default value if not set.\n"
305
+ " * @param {number} index The index to lookup.\n",
306
+ "name", field->name());
307
+ printer->Print(
308
+ " * @return {$opt$$type$} The value.\n"
309
+ " */\n",
310
+ "opt", type_is_primitive ? "" : "!",
311
+ "type", type);
312
+ printer->Print(
313
+ "$prefix$.prototype.get$field$OrDefault = function(index) {\n",
314
+ "prefix", JsFullName(field->containing_type()->file(),
315
+ field->containing_type()->full_name()),
316
+ "field", upper_name);
317
+ printer->Indent();
318
+ printer->Print(
319
+ "return /** @type {$opt$$type$} */ (",
320
+ "opt", type_is_primitive ? "" : "!",
321
+ "type", type);
322
+ printer->Print(
323
+ "this.get$$ValueOrDefault($number$, "
324
+ "index));\n",
325
+ "number", number.str());
326
+ printer->Outdent();
327
+ printer->Print(
328
+ "};\n"
329
+ "\n");
330
+ } else {
331
+ printer->Print(
332
+ "\n"
333
+ "/**\n"
334
+ " * Gets the value of the $name$ field.\n",
335
+ "name", field->name());
336
+ printer->Print(
337
+ " * @return {$opt$$type$} The value.\n"
338
+ " */\n",
339
+ "opt", type_is_primitive ? "?" : "",
340
+ "type", type);
341
+ printer->Print(
342
+ "$prefix$.prototype.get$field$ = function() {\n",
343
+ "prefix", JsFullName(field->containing_type()->file(),
344
+ field->containing_type()->full_name()),
345
+ "field", upper_name);
346
+ printer->Indent();
347
+ printer->Print(
348
+ "return /** @type {$opt$$type$} */ ",
349
+ "opt", type_is_primitive ? "?" : "",
350
+ "type", type);
351
+ printer->Print(
352
+ "(this.get$$Value($number$));\n",
353
+ "number", number.str());
354
+ printer->Outdent();
355
+ printer->Print(
356
+ "};\n"
357
+ "\n");
358
+
359
+ printer->Print(
360
+ "\n"
361
+ "/**\n"
362
+ " * Gets the value of the $name$ field or the default value if not "
363
+ "set.\n",
364
+ "name", field->name());
365
+ printer->Print(
366
+ " * @return {$opt$$type$} The value.\n"
367
+ " */\n",
368
+ "opt", type_is_primitive ? "" : "!",
369
+ "type", type);
370
+ printer->Print(
371
+ "$prefix$.prototype.get$field$OrDefault = function() {\n",
372
+ "prefix", JsFullName(field->containing_type()->file(),
373
+ field->containing_type()->full_name()),
374
+ "field", upper_name);
375
+ printer->Indent();
376
+ printer->Print(
377
+ "return /** @type {$opt$$type$} */ (",
378
+ "opt", type_is_primitive ? "" : "!",
379
+ "type", type);
380
+ printer->Print(
381
+ "this.get$$ValueOrDefault($number$));\n",
382
+ "number", number.str());
383
+ printer->Outdent();
384
+ printer->Print(
385
+ "};\n"
386
+ "\n");
387
+ }
388
+
389
+ // set
390
+ if (field->label() != google::protobuf::FieldDescriptor::LABEL_REPEATED) {
391
+ printer->Print("\n"
392
+ "/**\n"
393
+ " * Sets the value of the $name$ field.\n",
394
+ "name", field->name());
395
+ printer->Print(" * @param {$opt$$type$} value The value.\n"
396
+ " */\n",
397
+ "opt", type_is_primitive ? "" : "!",
398
+ "type", type);
399
+ printer->Print("$prefix$.prototype.set$field$ = function(value) {\n",
400
+ "prefix", JsFullName(field->containing_type()->file(),
401
+ field->containing_type()->full_name()),
402
+ "field", upper_name);
403
+ printer->Indent();
404
+ printer->Print(
405
+ "this.set$$Value($number$, value);\n",
406
+ "number", number.str());
407
+ printer->Outdent();
408
+ printer->Print("};\n"
409
+ "\n");
410
+ }
411
+
412
+ // add, Array
413
+ if (field->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) {
414
+ printer->Print("\n"
415
+ "/**\n"
416
+ " * Adds a value to the $name$ field.\n",
417
+ "name", field->name());
418
+ printer->Print(" * @param {$opt$$type$} value The value to add.\n"
419
+ " */\n",
420
+ "opt", type_is_primitive ? "" : "!",
421
+ "type", type);
422
+ printer->Print("$prefix$.prototype.add$field$ = function(value) {\n",
423
+ "prefix", JsFullName(field->containing_type()->file(),
424
+ field->containing_type()->full_name()),
425
+ "field", upper_name);
426
+ printer->Indent();
427
+ printer->Print(
428
+ "this.add$$Value($number$, value);\n",
429
+ "number", number.str());
430
+ printer->Outdent();
431
+ printer->Print("};\n"
432
+ "\n");
433
+
434
+ printer->Print("\n"
435
+ "/**\n"
436
+ " * Returns the array of values in the $name$ field.\n",
437
+ "name", field->name());
438
+ printer->Print(
439
+ " * @return {!Array.<$opt$$type$>} The values in the field.\n"
440
+ " */\n",
441
+ "opt", type_is_primitive ? "" : "!",
442
+ "type", type);
443
+ printer->Print("$prefix$.prototype.$field$Array = function() {\n",
444
+ "prefix", JsFullName(field->containing_type()->file(),
445
+ field->containing_type()->full_name()),
446
+ "field", field->camelcase_name());
447
+ printer->Indent();
448
+ printer->Print(
449
+ "return /** @type {!Array.<$opt$$type$>} */ (",
450
+ "type", type,
451
+ "opt", type_is_primitive ? "" : "!");
452
+ printer->Print(
453
+ "this.array$$Values($number$));"
454
+ "\n",
455
+ "number", number.str());
456
+ printer->Outdent();
457
+ printer->Print("};\n"
458
+ "\n");
459
+ }
460
+
461
+ // has
462
+ printer->Print("\n"
463
+ "/**\n"
464
+ " * @return {boolean} Whether the $name$ field has a value.\n"
465
+ " */\n",
466
+ "name", field->name());
467
+ printer->Print("$prefix$.prototype.has$field$ = function() {\n",
468
+ "prefix", JsFullName(field->containing_type()->file(),
469
+ field->containing_type()->full_name()),
470
+ "field", upper_name);
471
+ printer->Indent();
472
+ printer->Print("return this.has$$Value($number$);\n",
473
+ "number", number.str());
474
+ printer->Outdent();
475
+ printer->Print("};\n"
476
+ "\n");
477
+
478
+ // count
479
+ printer->Print(
480
+ "\n"
481
+ "/**\n"
482
+ " * @return {number} The number of values in the $name$ field.\n"
483
+ " */\n",
484
+ "name", field->name());
485
+ printer->Print("$prefix$.prototype.$field$Count = function() {\n",
486
+ "prefix", JsFullName(field->containing_type()->file(),
487
+ field->containing_type()->full_name()),
488
+ "field", field->camelcase_name());
489
+ printer->Indent();
490
+ printer->Print("return this.count$$Values($number$);\n",
491
+ "number", number.str());
492
+ printer->Outdent();
493
+ printer->Print("};\n"
494
+ "\n");
495
+
496
+ // clear
497
+ printer->Print("\n"
498
+ "/**\n"
499
+ " * Clears the values in the $name$ field.\n"
500
+ " */\n",
501
+ "name", field->name());
502
+ printer->Print("$prefix$.prototype.clear$field$ = function() {\n",
503
+ "prefix", JsFullName(field->containing_type()->file(),
504
+ field->containing_type()->full_name()),
505
+ "field", upper_name);
506
+ printer->Indent();
507
+ printer->Print("this.clear$$Field($number$);\n",
508
+ "number", number.str());
509
+ printer->Outdent();
510
+ printer->Print("};\n");
511
+ }
512
+
513
+ void CodeGenerator::GenEnumDescriptor(
514
+ const google::protobuf::EnumDescriptor *enum_desc,
515
+ google::protobuf::io::Printer *printer) {
516
+ printer->Print("\n"
517
+ "\n"
518
+ "/**\n"
519
+ " * Enumeration $name$.\n"
520
+ " * @enum {number}\n"
521
+ " */\n",
522
+ "name", enum_desc->name());
523
+ printer->Print("$name$ = {\n",
524
+ "name", JsFullName(enum_desc->file(),
525
+ enum_desc->full_name()));
526
+ printer->Indent();
527
+ for (int i = 0; i < enum_desc->value_count(); ++i) {
528
+ std::string format = "$key$: $value$,\n";
529
+ if (i == enum_desc->value_count() - 1) {
530
+ format = "$key$: $value$\n";
531
+ }
532
+ std::ostringstream number;
533
+ number << enum_desc->value(i)->number();
534
+ printer->Print(format.c_str(),
535
+ "key", enum_desc->value(i)->name(),
536
+ "value", number.str());
537
+ }
538
+ printer->Outdent();
539
+ printer->Print("};\n"
540
+ "\n"
541
+ "\n");
542
+ }
543
+
544
+ void CodeGenerator::GenDescriptorMetadata(
545
+ const google::protobuf::Descriptor *message,
546
+ google::protobuf::io::Printer *printer) {
547
+ printer->Print("\n"
548
+ "\n"
549
+ "goog.proto2.Message.set$$Metadata($name$, {\n",
550
+ "name", JsFullName(message->file(),
551
+ message->full_name()));
552
+ printer->Indent();
553
+ printer->Print("0: {\n");
554
+ printer->Indent();
555
+ printer->Print("name: '$name$',\n",
556
+ "name", message->name());
557
+ if (message->containing_type() != NULL) {
558
+ printer->Print("containingType: $type$,\n",
559
+ "type",
560
+ JsFullName(message->containing_type()->file(),
561
+ message->containing_type()->full_name()));
562
+ }
563
+ printer->Print("fullName: '$fullname$'\n",
564
+ "fullname", message->full_name());
565
+ printer->Outdent();
566
+ if (message->field_count() > 0) {
567
+ printer->Print("},\n");
568
+ } else {
569
+ printer->Print("}\n");
570
+ }
571
+ // fields
572
+ for (int i = 0; i < message->field_count(); ++i) {
573
+ CodeGenerator::GenFieldDescriptorMetadata(
574
+ message->field(i),
575
+ printer);
576
+ if (i != message->field_count() - 1) {
577
+ printer->Print(",\n");
578
+ } else {
579
+ printer->Print("\n");
580
+ }
581
+ }
582
+ printer->Outdent();
583
+ printer->Print("});\n");
584
+
585
+ // nested messages (recursively process)
586
+ for (int i = 0; i < message->nested_type_count(); ++i) {
587
+ CodeGenerator::GenDescriptorMetadata(
588
+ message->nested_type(i),
589
+ printer);
590
+ }
591
+ }
592
+
593
+ void CodeGenerator::GenFieldDescriptorMetadata(
594
+ const google::protobuf::FieldDescriptor *field,
595
+ google::protobuf::io::Printer *printer) {
596
+ std::ostringstream number;
597
+ number << field->number();
598
+
599
+ std::ostringstream default_value;
600
+ std::string js_type;
601
+ bool as_number = field->options().GetExtension(jstype);
602
+ if (field->type() == google::protobuf::FieldDescriptor::TYPE_DOUBLE) {
603
+ js_type = "DOUBLE";
604
+ default_value << field->default_value_double();
605
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_FLOAT) {
606
+ js_type = "FLOAT";
607
+ default_value << field->default_value_float();
608
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_INT64) {
609
+ js_type = "INT64";
610
+ if (as_number) {
611
+ default_value << field->default_value_int64();
612
+ } else {
613
+ default_value << "'" << field->default_value_int64() << "'";
614
+ }
615
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_UINT64) {
616
+ js_type = "UINT64";
617
+ if (as_number) {
618
+ default_value << field->default_value_uint64();
619
+ } else {
620
+ default_value << "'" << field->default_value_uint64() << "'";
621
+ }
622
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_INT32) {
623
+ js_type = "INT32";
624
+ default_value << field->default_value_uint32();
625
+ } else if (
626
+ field->type() == google::protobuf::FieldDescriptor::TYPE_FIXED64) {
627
+ js_type = "FIXED64";
628
+ if (as_number) {
629
+ default_value << field->default_value_uint64();
630
+ } else {
631
+ default_value << "'" << field->default_value_uint64() << "'";
632
+ }
633
+ } else if (
634
+ field->type() == google::protobuf::FieldDescriptor::TYPE_FIXED32) {
635
+ js_type = "FIXED32";
636
+ default_value << field->default_value_uint32();
637
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_BOOL) {
638
+ js_type = "BOOL";
639
+ default_value << field->default_value_bool();
640
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
641
+ js_type = "STRING";
642
+ default_value << "'" << field->default_value_string() << "'";
643
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_GROUP) {
644
+ js_type = "GROUP";
645
+ } else if (
646
+ field->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE) {
647
+ js_type = "MESSAGE";
648
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_BYTES) {
649
+ js_type = "BYTES";
650
+ default_value << "'" << field->default_value_string() << "'";
651
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_UINT32) {
652
+ js_type = "UINT32";
653
+ default_value << field->default_value_uint32();
654
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_ENUM) {
655
+ js_type = "ENUM";
656
+
657
+ default_value << JsFullName(field->enum_type()->file(),
658
+ field->enum_type()->full_name() + "." +
659
+ field->default_value_enum()->name());
660
+ } else if (
661
+ field->type() == google::protobuf::FieldDescriptor::TYPE_SFIXED32) {
662
+ js_type = "SFIXED32";
663
+ default_value << field->default_value_int32();
664
+ } else if (
665
+ field->type() == google::protobuf::FieldDescriptor::TYPE_SFIXED64) {
666
+ js_type = "SFIXED64";
667
+ if (as_number) {
668
+ default_value << field->default_value_int64();
669
+ } else {
670
+ default_value << "'" << field->default_value_int64() << "'";
671
+ }
672
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_SINT32) {
673
+ js_type = "SINT32";
674
+ default_value << field->default_value_int32();
675
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_SINT64) {
676
+ js_type = "SINT64";
677
+ if (as_number) {
678
+ default_value << field->default_value_int64();
679
+ } else {
680
+ default_value << "'" << field->default_value_int64() << "'";
681
+ }
682
+ }
683
+
684
+ std::string js_object;
685
+ if (field->type() == google::protobuf::FieldDescriptor::TYPE_BOOL) {
686
+ js_object = "Boolean";
687
+ } else if (
688
+ field->type() == google::protobuf::FieldDescriptor::TYPE_BYTES ||
689
+ field->type() == google::protobuf::FieldDescriptor::TYPE_STRING ||
690
+ ((field->type() == google::protobuf::FieldDescriptor::TYPE_INT64 ||
691
+ field->type() == google::protobuf::FieldDescriptor::TYPE_UINT64 ||
692
+ field->type() == google::protobuf::FieldDescriptor::TYPE_SINT64 ||
693
+ field->type() == google::protobuf::FieldDescriptor::TYPE_FIXED64 ||
694
+ field->type() == google::protobuf::FieldDescriptor::TYPE_SFIXED64) &&
695
+ !as_number)) {
696
+ js_object = "String";
697
+ } else if (
698
+ field->type() == google::protobuf::FieldDescriptor::TYPE_GROUP ||
699
+ field->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE) {
700
+ js_object = JsFullName(field->message_type()->file(),
701
+ field->message_type()->full_name());
702
+ } else if (field->type() == google::protobuf::FieldDescriptor::TYPE_ENUM) {
703
+ js_object = JsFullName(field->enum_type()->file(),
704
+ field->enum_type()->full_name());
705
+ } else {
706
+ js_object = "Number";
707
+ }
708
+
709
+ printer->Print("$number$: {\n",
710
+ "number", number.str());
711
+ printer->Indent();
712
+ printer->Print("name: '$name$',\n",
713
+ "name", field->name());
714
+ if (field->is_repeated()) {
715
+ printer->Print("repeated: true,\n");
716
+ }
717
+ printer->Print("fieldType: goog.proto2.Message.FieldType.$js_type$,\n",
718
+ "js_type", js_type);
719
+ if (field->has_default_value() ||
720
+ field->type() == google::protobuf::FieldDescriptor::TYPE_ENUM) {
721
+ printer->Print("defaultValue: $default$,\n",
722
+ "default", default_value.str());
723
+ }
724
+ printer->Print("type: $type$\n",
725
+ "type", js_object);
726
+ printer->Outdent();
727
+ printer->Print("}");
728
+ }
729
+
730
+ } // namespace js
731
+ } // namespace protobuf
732
+ } // namespace sg