Skip to content

Commit faa153e

Browse files
committed
Made the insertion points optional and fixed Json generator
1 parent 5c9fa1c commit faa153e

File tree

5 files changed

+270
-117
lines changed

5 files changed

+270
-117
lines changed

library/DrSlump/Protobuf/Compiler/Cli.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ public static function runProtoc($pluginExecutable)
128128
$args['options'][$parts[0]] = $parts[1];
129129
}
130130
}
131+
if ($result->options['insertions']) {
132+
$args['options']['insertions'] = 1;
133+
}
131134

132135
$cmd[] = '--php_out=' .
133136
escapeshellarg(
@@ -203,6 +206,12 @@ public static function parseArguments()
203206
'description' => 'port .proto comments to generated code',
204207
));
205208

209+
$main->addOption('insertions', array(
210+
'long_name' => '--insertions',
211+
'action' => 'StoreTrue',
212+
'description' => 'generate @@protoc insertion points',
213+
));
214+
206215
$main->addOption('define', array(
207216
'short_name' => '-D',
208217
'long_name' => '--define',

library/DrSlump/Protobuf/Compiler/JsonGenerator.php

Lines changed: 185 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,164 @@
77

88
class JsonGenerator extends AbstractGenerator
99
{
10-
public function getNamespace(proto\FileDescriptorProto $proto)
10+
/**
11+
* Get an option from the compiler arguments or from the proto file.
12+
*
13+
* @param string $name
14+
* @return string|null
15+
*/
16+
protected function getOption($name)
1117
{
12-
$namespace = $proto->getPackage();
13-
$opts = $proto->getOptions();
14-
if (isset($opts['json.package'])) {
15-
$namespace = $opts['jsonpackage'];
18+
$opt = $this->compiler->getOption($name);
19+
20+
if (NULL === $opt) {
21+
$opts = $this->proto->getOptions();
22+
if (!empty($opts) && isset($opts['json.' . $name])) {
23+
$opt = $opts['json.' . $name];
24+
}
1625
}
17-
if (isset($opts['json.namespace'])) {
26+
27+
return $opt;
28+
}
29+
30+
31+
public function getNamespace(proto\FileDescriptorProto $proto = NULL)
32+
{
33+
$proto = $proto ?: $this->proto;
34+
35+
$opts = $proto->getOptions();
36+
if ($this->compiler->getOption('namespace')) {
37+
$namespace = $this->compiler->getOption('namespace');
38+
} else if (isset($opts['json.namespace'])) {
1839
$namespace = $opts['json.namespace'];
40+
} else if (isset($opts['json.package'])) {
41+
$namespace = $opts['json.package'];
42+
} else {
43+
$namespace = parent::getNamespace($proto);
1944
}
2045

2146
$namespace = trim($namespace, '.');
2247
return $namespace;
2348
}
2449

50+
51+
public function generate(proto\FileDescriptorProto $proto)
52+
{
53+
parent::generate($proto);
54+
55+
56+
57+
}
58+
59+
protected function buildFile(proto\FileDescriptorProto $proto, $fname, $contents)
60+
{
61+
$suffix = $this->getOption('suffix') ?: '.js';
62+
$fname .= $suffix;
63+
64+
$file = new \google\protobuf\compiler\CodeGeneratorResponse\File();
65+
$file->setName($fname);
66+
67+
$s = array();
68+
$s[]= "// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin " . Protobuf::VERSION;
69+
$s[]= "// Source: " . $proto->getName();
70+
$s[]= "// Date: " . gmdate('Y-m-d H:i:s');
71+
$s[]= "";
72+
$s[]= "// @@protoc_insertion_point(scope_file)";
73+
$s[]= "";
74+
$s[]= "(function(){";
75+
$s[]= "";
76+
$s[]= " /** @namespace */";
77+
$s[]= " var $namespace = $namespace || {};";
78+
$s[]= "";
79+
$s[]= " // Make it CommonJS compatible";
80+
$s[]= " if (typeof exports !== 'undefined') {";
81+
$s[]= " var ProtoJson = this.ProtoJson;";
82+
$s[]= " if (!ProtoJson && typeof require !== 'undefined') {";
83+
$s[]= " ProtoJson = require('ProtoJson');";
84+
$s[]= " }";
85+
$s[]= " $namespace = exports;";
86+
$s[]= " } else {";
87+
$s[]= " this.$namespace = $namespace;";
88+
$s[]= " }";
89+
$s[]= "";
90+
$s[]= $contents;
91+
$s[]= "";
92+
$s[]= "})();";
93+
$s[]= "";
94+
95+
$contents = implode(PHP_EOL, $s) . PHP_EOL . $contents;
96+
$file->setContent($contents);
97+
return $file;
98+
}
99+
100+
public function compileProtoFile(proto\FileDescriptorProto $proto)
101+
{
102+
$file = new \google\protobuf\compiler\CodeGeneratorResponse\File();
103+
104+
$opts = $proto->getOptions();
105+
$name = pathinfo($proto->getName(), PATHINFO_FILENAME);
106+
$name .= isset($opts['json.suffix'])
107+
? $opts['json.suffix']
108+
: '.js';
109+
$file->setName($name);
110+
111+
$namespace = $this->getNamespace($proto);
112+
113+
$s[]= "// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin " . Protobuf::VERSION;
114+
$s[]= "// Source: " . $proto->getName();
115+
$s[]= "// Date: " . date('Y-m-d H:i:s');
116+
$s[]= "";
117+
118+
$s[]= "(function(){";
119+
$s[]= "/** @namespace */";
120+
$s[]= "var $namespace = $namespace || {};";
121+
$s[]= "";
122+
$s[]= "// Make it CommonJS compatible";
123+
$s[]= "if (typeof exports !== 'undefined') {";
124+
$s[]= " var ProtoJson = this.ProtoJson;";
125+
$s[]= " if (!ProtoJson && typeof require !== 'undefined')";
126+
$s[]= " ProtoJson = require('ProtoJson');";
127+
$s[]= " $namespace = exports;";
128+
$s[]= "} else {";
129+
$s[]= " this.$namespace = $namespace;";
130+
$s[]= "}";
131+
$s[]= "";
132+
133+
134+
// Generate Enums
135+
foreach ($proto->getEnumTypeList() as $enum) {
136+
$s[]= $this->compileEnum($enum, $namespace);
137+
}
138+
139+
// Generate Messages
140+
foreach ($proto->getMessageTypeList() as $msg) {
141+
$s[] = $this->compileMessage($msg, $namespace);
142+
}
143+
144+
// Collect extensions
145+
if ($proto->hasExtension()) {
146+
foreach ($proto->getExtensionList() as $field) {
147+
$this->extensions[$field->getExtendee()][] = array($namespace, $field);
148+
}
149+
}
150+
151+
// Dump all extensions found in this proto file
152+
if (count($this->extensions)) {
153+
foreach ($this->extensions as $extendee => $fields) {
154+
foreach ($fields as $pair) {
155+
list($ns, $field) = $pair;
156+
$s[]= $this->compileExtension($field, $ns, '');
157+
}
158+
}
159+
}
160+
161+
$s[]= "})();";
162+
163+
$src = implode("\n", $s);
164+
$file->setContent($src);
165+
return array($file);
166+
}
167+
25168
public function compileEnum(proto\EnumDescriptorProto $enum, $namespace)
26169
{
27170
$s[]= "$namespace.$enum->name = {";
@@ -103,73 +246,6 @@ public function compileMessage(proto\DescriptorProto $msg, $namespace)
103246
return implode("\n", $s);
104247
}
105248

106-
public function compileProtoFile(proto\FileDescriptorProto $proto)
107-
{
108-
$file = new proto\compiler\CodeGeneratorResponse\File();
109-
110-
$opts = $proto->getOptions();
111-
$name = pathinfo($proto->getName(), PATHINFO_FILENAME);
112-
$name .= isset($opts['json.suffix'])
113-
? $opts['json.suffix']
114-
: '.js';
115-
$file->setName($name);
116-
117-
$namespace = $this->getNamespace($proto);
118-
119-
$s[]= "// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin " . Protobuf::VERSION;
120-
$s[]= "// Source: " . $proto->getName();
121-
$s[]= "// Date: " . date('Y-m-d H:i:s');
122-
$s[]= "";
123-
124-
$s[]= "(function(){";
125-
$s[]= "/** @namespace */";
126-
$s[]= "var $namespace = $namespace || {};";
127-
$s[]= "";
128-
$s[]= "// Make it CommonJS compatible";
129-
$s[]= "if (typeof exports !== 'undefined') {";
130-
$s[]= " var ProtoJson = this.ProtoJson;";
131-
$s[]= " if (!ProtoJson && typeof require !== 'undefined')";
132-
$s[]= " ProtoJson = require('ProtoJson');";
133-
$s[]= " $namespace = exports;";
134-
$s[]= "} else {";
135-
$s[]= " this.$namespace = $namespace;";
136-
$s[]= "}";
137-
$s[]= "";
138-
139-
140-
// Generate Enums
141-
foreach ($proto->getEnumTypeList() as $enum) {
142-
$s[]= $this->compileEnum($enum, $namespace);
143-
}
144-
145-
// Generate Messages
146-
foreach ($proto->getMessageTypeList() as $msg) {
147-
$s[] = $this->compileMessage($msg, $namespace);
148-
}
149-
150-
// Collect extensions
151-
if ($proto->hasExtension()) {
152-
foreach ($proto->getExtensionList() as $field) {
153-
$this->extensions[$field->getExtendee()][] = array($namespace, $field);
154-
}
155-
}
156-
157-
// Dump all extensions found in this proto file
158-
if (count($this->extensions)) {
159-
foreach ($this->extensions as $extendee => $fields) {
160-
foreach ($fields as $pair) {
161-
list($ns, $field) = $pair;
162-
$s[]= $this->compileExtension($field, $ns, '');
163-
}
164-
}
165-
}
166-
167-
$s[]= "})();";
168-
169-
$src = implode("\n", $s);
170-
$file->setContent($src);
171-
return array($file);
172-
}
173249

174250
public function generateField(proto\FieldDescriptorProto $field)
175251
{
@@ -179,7 +255,7 @@ public function generateField(proto\FieldDescriptorProto $field)
179255
if (substr($reference, 0, 1) !== '.') {
180256
throw new \RuntimeException('Only fully qualified names are supported: ' . $reference);
181257
}
182-
$reference = "'" . $this->normalizeReference($reference) . "'";
258+
$reference = "'" . $this->normalizeNS($reference) . "'";
183259
}
184260

185261
$default = 'null';
@@ -192,7 +268,7 @@ public function generateField(proto\FieldDescriptorProto $field)
192268
$default = '"' . addcslashes($field->getDefaultValue(), '"\\') . '"';
193269
break;
194270
case Protobuf::TYPE_ENUM:
195-
$default = $this->normalizeReference($field->getTypeName()) . '.' . $field->getDefaultValue();
271+
$default = $this->normalizeNS($field->getTypeName()) . '.' . $field->getDefaultValue();
196272
break;
197273
default: // Numbers
198274
$default = $field->getDefaultValue();
@@ -213,7 +289,7 @@ public function generateField(proto\FieldDescriptorProto $field)
213289

214290
public function generateAccessors($field, $namespace)
215291
{
216-
$camel = $this->comp->camelize(ucfirst($field->getName()));
292+
$camel = $this->compiler->camelize(ucfirst($field->getName()));
217293

218294
$s[]= "/**";
219295
$s[]= " * Check <$field->name> value";
@@ -316,38 +392,49 @@ public function getJsDoc(proto\FieldDescriptorProto $field)
316392
case Protobuf::TYPE_STRING:
317393
return 'String';
318394
case Protobuf::TYPE_MESSAGE:
319-
return $this->normalizeReference($field->getTypeName());
395+
return $this->normalizeNS($field->getTypeName());
320396
case Protobuf::TYPE_BYTES:
321397
return 'String';
322398
case Protobuf::TYPE_ENUM:
323-
return 'Int (' . $this->normalizeReference($field->getTypeName()) . ')';
399+
return 'Int (' . $this->normalizeNS($field->getTypeName()) . ')';
324400

325401
case Protobuf::TYPE_GROUP:
326402
default:
327403
return 'unknown';
328404
}
329405
}
330406

331-
public function normalizeReference($reference)
407+
408+
protected function normalizeNS($package)
332409
{
333-
// Remove leading dot
334-
$reference = ltrim($reference, '.');
335-
336-
if (!$this->comp->hasPackage($reference)) {
337-
$found = false;
338-
foreach ($this->comp->getPackages() as $package=>$namespace) {
339-
if (0 === strpos($reference, $package.'.')) {
340-
$reference = $namespace . substr($reference, strlen($package));
341-
$found = true;
342-
}
343-
}
344-
if (!$found) {
345-
$this->comp->warning('Non tracked package name found "' . $reference . '"');
346-
}
347-
} else {
348-
$reference = $this->comp->getPackage($reference);
349-
}
350-
351-
return $reference;
410+
// Remove leading dot (used in references)
411+
$package = ltrim($package, '.');
412+
413+
if ($this->compiler->hasPackage($package)) {
414+
return $this->compiler->getPackage($package);
415+
}
416+
417+
// Check the currently registered packages to find a root one
418+
$found = null;
419+
foreach ($this->compiler->getPackages() as $pkg=>$ns) {
420+
// Keep only the longest match
421+
if (0 === strpos($package, $pkg.'.') && strlen($found) < strlen($pkg)) {
422+
$found = $pkg;
423+
}
424+
}
425+
426+
// If no matching package was found issue a warning and use the package name
427+
if (!$found) {
428+
$this->compiler->warning('Non tracked package name found "' . $package . '"');
429+
$namespace = $package;
430+
} else {
431+
// Complete the namespace with the remaining package
432+
$namespace = $this->compiler->getPackage($found);
433+
$namespace .= substr($package, strlen($found));
434+
// Set the newly found namespace in the registry
435+
$this->compiler->setPackage($package, $namespace);
436+
}
437+
438+
return $namespace;
352439
}
353440
}

0 commit comments

Comments
 (0)