2 module.exports = proto_target;
4 proto_target.private = true;
6 var protobuf = require("../..");
8 var Namespace = protobuf.Namespace,
11 Field = protobuf.Field,
12 OneOf = protobuf.OneOf,
13 Service = protobuf.Service,
14 Method = protobuf.Method,
15 types = protobuf.types,
18 function underScore(str) {
19 return str.substring(0,1)
21 .replace(/([A-Z])(?=[a-z]|$)/g, function($0, $1) { return "_" + $1.toLowerCase(); });
29 function proto_target(root, options, callback) {
31 switch (options.syntax) {
42 return callback(Error("invalid syntax: " + options.syntax));
49 return callback(null, out.join("\n"));
63 for (var i = 0; i < indent; ++i)
69 function escape(str) {
70 return str.replace(/[\\"']/g, "\\$&")
71 .replace(/\r/g, "\\r")
72 .replace(/\n/g, "\\n")
73 .replace(/\u0000/g, "\\0"); // eslint-disable-line no-control-regex
79 return v ? "true" : "false";
83 return "\"" + escape(String(v)) + "\"";
87 function buildRoot(root) {
93 var nested = ptr.nestedArray;
94 if (nested.length === 1 && nested[0] instanceof Namespace && !(nested[0] instanceof Type || nested[0] instanceof Service)) {
101 out.push("syntax = \"proto" + syntax + "\";");
103 out.push("", "package " + pkg.join(".") + ";");
106 ptr.nestedArray.forEach(build);
109 function build(object) {
110 if (object instanceof Enum)
112 else if (object instanceof Type)
114 else if (object instanceof Field)
116 else if (object instanceof OneOf)
118 else if (object instanceof Service)
119 buildService(object);
120 else if (object instanceof Method)
123 buildNamespace(object);
126 function buildNamespace(namespace) { // just a namespace, not a type etc.
128 push("message " + namespace.name + " {");
130 buildOptions(namespace);
131 consolidateExtends(namespace.nestedArray).remaining.forEach(build);
136 function buildEnum(enm) {
138 push("enum " + enm.name + " {");
140 ++indent; first = true;
141 Object.keys(enm.values).forEach(function(name) {
142 var val = enm.values[name];
147 push(name + " = " + val + ";");
149 --indent; first = false;
153 function buildRanges(keyword, ranges) {
154 if (ranges && ranges.length) {
156 ranges.forEach(function(range) {
157 if (typeof range === "string")
158 parts.push("\"" + escape(range) + "\"");
159 else if (range[0] === range[1])
160 parts.push(range[0]);
162 parts.push(range[0] + " to " + (range[1] === 0x1FFFFFFF ? "max" : range[1]));
165 push(keyword + " " + parts.join(", ") + ";");
169 function buildType(type) {
171 return; // built with the sister-field
173 push("message " + type.name + " {");
176 type.oneofsArray.forEach(build);
178 type.fieldsArray.forEach(build);
179 consolidateExtends(type.nestedArray).remaining.forEach(build);
180 buildRanges("extensions", type.extensions);
181 buildRanges("reserved", type.reserved);
186 function buildField(field, passExtend) {
187 if (field.partOf || field.declaringField || field.extend !== undefined && !passExtend)
193 if (field.resolvedType && field.resolvedType.group) {
199 sb.push("map<" + field.keyType + ", " + field.type + ">");
200 else if (field.repeated)
201 sb.push("repeated", field.type);
202 else if (syntax === 2 || field.parent.group)
203 sb.push(field.required ? "required" : "optional", field.type);
206 sb.push(underScore(field.name), "=", field.id);
207 var opts = buildFieldOptions(field);
210 push(sb.join(" ") + ";");
213 function buildGroup(field) {
214 push(field.rule + " group " + field.resolvedType.name + " = " + field.id + " {");
216 buildOptions(field.resolvedType);
218 field.resolvedType.fieldsArray.forEach(function(field) {
225 function buildFieldOptions(field) {
227 if (!field.options || !(keys = Object.keys(field.options)).length)
230 keys.forEach(function(key) {
231 var val = field.options[key];
232 var wireType = types.packed[field.resolvedType instanceof Enum ? "int32" : field.type];
236 // skip when not packable or syntax default
237 if (wireType === undefined || syntax === 3 === val)
243 // skip default (resolved) default values
244 if (field.long && !util.longNeq(field.defaultValue, types.defaults[field.type]) || !field.long && field.defaultValue === types.defaults[field.type])
246 // enum defaults specified as strings are type references and not enclosed in quotes
247 if (field.resolvedType instanceof Enum)
249 // otherwise fallthrough
254 sb.push(key + "=" + val);
257 ? "[" + sb.join(", ") + "]"
261 function consolidateExtends(nested) {
263 nested = nested.filter(function(obj) {
264 if (!(obj instanceof Field) || obj.extend === undefined)
266 (ext[obj.extend] || (ext[obj.extend] = [])).push(obj);
269 Object.keys(ext).forEach(function(extend) {
271 push("extend " + extend + " {");
272 ++indent; first = true;
273 ext[extend].forEach(function(field) {
274 buildField(field, true);
284 function buildOneOf(oneof) {
286 push("oneof " + underScore(oneof.name) + " {");
287 ++indent; first = true;
288 oneof.oneof.forEach(function(fieldName) {
289 var field = oneof.parent.get(fieldName);
294 var opts = buildFieldOptions(field);
295 push(field.type + " " + underScore(field.name) + " = " + field.id + (opts ? " " + opts : "") + ";");
301 function buildService(service) {
302 push("service " + service.name + " {");
304 service.methodsArray.forEach(build);
305 consolidateExtends(service.nestedArray).remaining.forEach(build);
310 function buildMethod(method) {
311 push(method.type + " " + method.name + " (" + (method.requestStream ? "stream " : "") + method.requestType + ") returns (" + (method.responseStream ? "stream " : "") + method.responseType + ");");
314 function buildOptions(object) {
318 Object.keys(object.options).forEach(function(key) {
323 var val = object.options[key];
324 push("option " + key + " = " + JSON.stringify(val) + ";");