Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / protobufjs / cli / targets / proto.js
diff --git a/legacy-libs/protobufjs/cli/targets/proto.js b/legacy-libs/protobufjs/cli/targets/proto.js
new file mode 100644 (file)
index 0000000..d633f16
--- /dev/null
@@ -0,0 +1,326 @@
+"use strict";
+module.exports = proto_target;
+
+proto_target.private = true;
+
+var protobuf = require("../..");
+
+var Namespace  = protobuf.Namespace,
+    Enum       = protobuf.Enum,
+    Type       = protobuf.Type,
+    Field      = protobuf.Field,
+    OneOf      = protobuf.OneOf,
+    Service    = protobuf.Service,
+    Method     = protobuf.Method,
+    types      = protobuf.types,
+    util       = protobuf.util;
+
+function underScore(str) {
+    return str.substring(0,1)
+         + str.substring(1)
+               .replace(/([A-Z])(?=[a-z]|$)/g, function($0, $1) { return "_" + $1.toLowerCase(); });
+}
+
+var out = [];
+var indent = 0;
+var first = false;
+var syntax = 3;
+
+function proto_target(root, options, callback) {
+    if (options) {
+        switch (options.syntax) {
+            case undefined:
+            case "proto3":
+            case "3":
+                syntax = 3;
+                break;
+            case "proto2":
+            case "2":
+                syntax = 2;
+                break;
+            default:
+                return callback(Error("invalid syntax: " + options.syntax));
+        }
+    }
+    indent = 0;
+    first = false;
+    try {
+        buildRoot(root);
+        return callback(null, out.join("\n"));
+    } catch (err) {
+        return callback(err);
+    } finally {
+        out = [];
+        syntax = 3;
+    }
+}
+
+function push(line) {
+    if (line === "")
+        out.push("");
+    else {
+        var ind = "";
+        for (var i = 0; i < indent; ++i)
+            ind += "    ";
+        out.push(ind + line);
+    }
+}
+
+function escape(str) {
+    return str.replace(/[\\"']/g, "\\$&")
+              .replace(/\r/g, "\\r")
+              .replace(/\n/g, "\\n")
+              .replace(/\u0000/g, "\\0"); // eslint-disable-line no-control-regex
+}
+
+function value(v) {
+    switch (typeof v) {
+        case "boolean":
+            return v ? "true" : "false";
+        case "number":
+            return v.toString();
+        default:
+            return "\"" + escape(String(v)) + "\"";
+    }
+}
+
+function buildRoot(root) {
+    root.resolveAll();
+    var pkg = [];
+    var ptr = root;
+    var repeat = true;
+    do {
+        var nested = ptr.nestedArray;
+        if (nested.length === 1 && nested[0] instanceof Namespace && !(nested[0] instanceof Type || nested[0] instanceof Service)) {
+            ptr = nested[0];
+            if (ptr !== root)
+                pkg.push(ptr.name);
+        } else
+            repeat = false;
+    } while (repeat);
+    out.push("syntax = \"proto" + syntax + "\";");
+    if (pkg.length)
+        out.push("", "package " + pkg.join(".") + ";");
+
+    buildOptions(ptr);
+    ptr.nestedArray.forEach(build);
+}
+
+function build(object) {
+    if (object instanceof Enum)
+        buildEnum(object);
+    else if (object instanceof Type)
+        buildType(object);
+    else if (object instanceof Field)
+        buildField(object);
+    else if (object instanceof OneOf)
+        buildOneOf(object);
+    else if (object instanceof Service)
+        buildService(object);
+    else if (object instanceof Method)
+        buildMethod(object);
+    else
+        buildNamespace(object);
+}
+
+function buildNamespace(namespace) { // just a namespace, not a type etc.
+    push("");
+    push("message " + namespace.name + " {");
+    ++indent;
+    buildOptions(namespace);
+    consolidateExtends(namespace.nestedArray).remaining.forEach(build);
+    --indent;
+    push("}");
+}
+
+function buildEnum(enm) {
+    push("");
+    push("enum " + enm.name + " {");
+    buildOptions(enm);
+    ++indent; first = true;
+    Object.keys(enm.values).forEach(function(name) {
+        var val = enm.values[name];
+        if (first) {
+            push("");
+            first = false;
+        }
+        push(name + " = " + val + ";");
+    });
+    --indent; first = false;
+    push("}");
+}
+
+function buildRanges(keyword, ranges) {
+    if (ranges && ranges.length) {
+        var parts = [];
+        ranges.forEach(function(range) {
+            if (typeof range === "string")
+                parts.push("\"" + escape(range) + "\"");
+            else if (range[0] === range[1])
+                parts.push(range[0]);
+            else
+                parts.push(range[0] + " to " + (range[1] === 0x1FFFFFFF ? "max" : range[1]));
+        });
+        push("");
+        push(keyword + " " + parts.join(", ") + ";");
+    }
+}
+
+function buildType(type) {
+    if (type.group)
+        return; // built with the sister-field
+    push("");
+    push("message " + type.name + " {");
+    ++indent;
+    buildOptions(type);
+    type.oneofsArray.forEach(build);
+    first = true;
+    type.fieldsArray.forEach(build);
+    consolidateExtends(type.nestedArray).remaining.forEach(build);
+    buildRanges("extensions", type.extensions);
+    buildRanges("reserved", type.reserved);
+    --indent;
+    push("}");
+}
+
+function buildField(field, passExtend) {
+    if (field.partOf || field.declaringField || field.extend !== undefined && !passExtend)
+        return;
+    if (first) {
+        first = false;
+        push("");
+    }
+    if (field.resolvedType && field.resolvedType.group) {
+        buildGroup(field);
+        return;
+    }
+    var sb = [];
+    if (field.map)
+        sb.push("map<" + field.keyType + ", " + field.type + ">");
+    else if (field.repeated)
+        sb.push("repeated", field.type);
+    else if (syntax === 2 || field.parent.group)
+        sb.push(field.required ? "required" : "optional", field.type);
+    else
+        sb.push(field.type);
+    sb.push(underScore(field.name), "=", field.id);
+    var opts = buildFieldOptions(field);
+    if (opts)
+        sb.push(opts);
+    push(sb.join(" ") + ";");
+}
+
+function buildGroup(field) {
+    push(field.rule + " group " + field.resolvedType.name + " = " + field.id + " {");
+    ++indent;
+    buildOptions(field.resolvedType);
+    first = true;
+    field.resolvedType.fieldsArray.forEach(function(field) {
+        buildField(field);
+    });
+    --indent;
+    push("}");
+}
+
+function buildFieldOptions(field) {
+    var keys;
+    if (!field.options || !(keys = Object.keys(field.options)).length)
+        return null;
+    var sb = [];
+    keys.forEach(function(key) {
+        var val = field.options[key];
+        var wireType = types.packed[field.resolvedType instanceof Enum ? "int32" : field.type];
+        switch (key) {
+            case "packed":
+                val = Boolean(val);
+                // skip when not packable or syntax default
+                if (wireType === undefined || syntax === 3 === val)
+                    return;
+                break;
+            case "default":
+                if (syntax === 3)
+                    return;
+                // skip default (resolved) default values
+                if (field.long && !util.longNeq(field.defaultValue, types.defaults[field.type]) || !field.long && field.defaultValue === types.defaults[field.type])
+                    return;
+                // enum defaults specified as strings are type references and not enclosed in quotes
+                if (field.resolvedType instanceof Enum)
+                    break;
+                // otherwise fallthrough
+            default:
+                val = value(val);
+                break;
+        }
+        sb.push(key + "=" + val);
+    });
+    return sb.length
+        ? "[" + sb.join(", ") + "]"
+        : null;
+}
+
+function consolidateExtends(nested) {
+    var ext = {};
+    nested = nested.filter(function(obj) {
+        if (!(obj instanceof Field) || obj.extend === undefined)
+            return true;
+        (ext[obj.extend] || (ext[obj.extend] = [])).push(obj);
+        return false;
+    });
+    Object.keys(ext).forEach(function(extend) {
+        push("");
+        push("extend " + extend + " {");
+        ++indent; first = true;
+        ext[extend].forEach(function(field) {
+            buildField(field, true);
+        });
+        --indent;
+        push("}");
+    });
+    return {
+        remaining: nested
+    };
+}
+
+function buildOneOf(oneof) {
+    push("");
+    push("oneof " + underScore(oneof.name) + " {");
+    ++indent; first = true;
+    oneof.oneof.forEach(function(fieldName) {
+        var field = oneof.parent.get(fieldName);
+        if (first) {
+            first = false;
+            push("");
+        }
+        var opts = buildFieldOptions(field);
+        push(field.type + " " + underScore(field.name) + " = " + field.id + (opts ? " " + opts : "") + ";");
+    });
+    --indent;
+    push("}");
+}
+
+function buildService(service) {
+    push("service " + service.name + " {");
+    ++indent;
+    service.methodsArray.forEach(build);
+    consolidateExtends(service.nestedArray).remaining.forEach(build);
+    --indent;
+    push("}");
+}
+
+function buildMethod(method) {
+    push(method.type + " " + method.name + " (" + (method.requestStream ? "stream " : "") + method.requestType + ") returns (" + (method.responseStream ? "stream " : "") + method.responseType + ");");
+}
+
+function buildOptions(object) {
+    if (!object.options)
+        return;
+    first = true;
+    Object.keys(object.options).forEach(function(key) {
+        if (first) {
+            first = false;
+            push("");
+        }
+        var val = object.options[key];
+        push("option " + key + " = " + JSON.stringify(val) + ";");
+    });
+}