protobuf-closure-library 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +8 -0
- data/Gemfile +4 -0
- data/README.rst +31 -0
- data/Rakefile +23 -0
- data/ext/protoc_js_core/code_generator.cc +732 -0
- data/ext/protoc_js_core/code_generator.h +81 -0
- data/ext/protoc_js_core/extconf.rb +28 -0
- data/ext/protoc_js_core/js/int64_encoding.proto +28 -0
- data/ext/protoc_js_core/js/javascript_package.proto +23 -0
- data/ext/protoc_js_core/protoc_js_core.cc +66 -0
- data/lib/protobuf-closure-library.rb +4 -0
- data/lib/protobuf-closure-library/config.rb +4 -0
- data/lib/protobuf-closure-library/protoc_js.rb +30 -0
- data/lib/protobuf-closure-library/version.rb +3 -0
- data/protobuf-closure-library.gemspec +29 -0
- data/test/proto/package_test.proto +17 -0
- data/test/proto/test.proto +81 -0
- data/test/protobuf_closure_library_test.rb +20 -0
- metadata +107 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rst
ADDED
@@ -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>`_.
|
data/Rakefile
ADDED
@@ -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
|