1
0
mirror of https://github.com/musix-org/musix-oss synced 2024-11-10 11:20:19 +00:00
musix-oss/node_modules/protobufjs/cli/pbjs.js
2020-03-03 22:30:50 +02:00

330 lines
12 KiB
JavaScript

"use strict";
var path = require("path"),
fs = require("fs"),
pkg = require("./package.json"),
util = require("./util");
util.setup();
var protobuf = require(util.pathToProtobufJs),
minimist = require("minimist"),
chalk = require("chalk"),
glob = require("glob");
var targets = util.requireAll("./targets");
/**
* Runs pbjs programmatically.
* @param {string[]} args Command line arguments
* @param {function(?Error, string=)} [callback] Optional completion callback
* @returns {number|undefined} Exit code, if known
*/
exports.main = function main(args, callback) {
var lintDefault = "eslint-disable " + [
"block-scoped-var",
"id-length",
"no-control-regex",
"no-magic-numbers",
"no-prototype-builtins",
"no-redeclare",
"no-shadow",
"no-var",
"sort-vars"
].join(", ");
var argv = minimist(args, {
alias: {
target: "t",
out: "o",
path: "p",
wrap: "w",
root: "r",
lint: "l",
// backward compatibility:
"force-long": "strict-long",
"force-message": "strict-message"
},
string: [ "target", "out", "path", "wrap", "dependency", "root", "lint" ],
boolean: [ "create", "encode", "decode", "verify", "convert", "delimited", "beautify", "comments", "es6", "sparse", "keep-case", "force-long", "force-number", "force-enum-string", "force-message" ],
default: {
target: "json",
create: true,
encode: true,
decode: true,
verify: true,
convert: true,
delimited: true,
beautify: true,
comments: true,
es6: null,
lint: lintDefault,
"keep-case": false,
"force-long": false,
"force-number": false,
"force-enum-string": false,
"force-message": false
}
});
var target = targets[argv.target],
files = argv._,
paths = typeof argv.path === "string" ? [ argv.path ] : argv.path || [];
// alias hyphen args in camel case
Object.keys(argv).forEach(function(key) {
var camelKey = key.replace(/-([a-z])/g, function($0, $1) { return $1.toUpperCase(); });
if (camelKey !== key)
argv[camelKey] = argv[key];
});
// protobuf.js package directory contains additional, otherwise non-bundled google types
paths.push(path.relative(process.cwd(), path.join(__dirname, "..")) || ".");
if (!files.length) {
var descs = Object.keys(targets).filter(function(key) { return !targets[key].private; }).map(function(key) {
return " " + util.pad(key, 14, true) + targets[key].description;
});
if (callback)
callback(Error("usage")); // eslint-disable-line callback-return
else
process.stderr.write([
"protobuf.js v" + pkg.version + " CLI for JavaScript",
"",
chalk.bold.white("Translates between file formats and generates static code."),
"",
" -t, --target Specifies the target format. Also accepts a path to require a custom target.",
"",
descs.join("\n"),
"",
" -p, --path Adds a directory to the include path.",
"",
" -o, --out Saves to a file instead of writing to stdout.",
"",
" --sparse Exports only those types referenced from a main file (experimental).",
"",
chalk.bold.gray(" Module targets only:"),
"",
" -w, --wrap Specifies the wrapper to use. Also accepts a path to require a custom wrapper.",
"",
" default Default wrapper supporting both CommonJS and AMD",
" commonjs CommonJS wrapper",
" amd AMD wrapper",
" es6 ES6 wrapper (implies --es6)",
" closure A closure adding to protobuf.roots where protobuf is a global",
"",
" --dependency Specifies which version of protobuf to require. Accepts any valid module id",
"",
" -r, --root Specifies an alternative protobuf.roots name.",
"",
" -l, --lint Linter configuration. Defaults to protobuf.js-compatible rules:",
"",
" " + lintDefault,
"",
" --es6 Enables ES6 syntax (const/let instead of var)",
"",
chalk.bold.gray(" Proto sources only:"),
"",
" --keep-case Keeps field casing instead of converting to camel case.",
"",
chalk.bold.gray(" Static targets only:"),
"",
" --no-create Does not generate create functions used for reflection compatibility.",
" --no-encode Does not generate encode functions.",
" --no-decode Does not generate decode functions.",
" --no-verify Does not generate verify functions.",
" --no-convert Does not generate convert functions like from/toObject",
" --no-delimited Does not generate delimited encode/decode functions.",
" --no-beautify Does not beautify generated code.",
" --no-comments Does not output any JSDoc comments.",
"",
" --force-long Enfores the use of 'Long' for s-/u-/int64 and s-/fixed64 fields.",
" --force-number Enfores the use of 'number' for s-/u-/int64 and s-/fixed64 fields.",
" --force-message Enfores the use of message instances instead of plain objects.",
"",
"usage: " + chalk.bold.green("pbjs") + " [options] file1.proto file2.json ..." + chalk.gray(" (or pipe) ") + "other | " + chalk.bold.green("pbjs") + " [options] -",
""
].join("\n"));
return 1;
}
if (typeof argv["strict-long"] === "boolean")
argv["force-long"] = argv["strict-long"];
// Resolve glob expressions
for (var i = 0; i < files.length;) {
if (glob.hasMagic(files[i])) {
var matches = glob.sync(files[i]);
Array.prototype.splice.apply(files, [i, 1].concat(matches));
i += matches.length;
} else
++i;
}
// Require custom target
if (!target)
target = require(path.resolve(process.cwd(), argv.target));
var root = new protobuf.Root();
var mainFiles = [];
// Search include paths when resolving imports
root.resolvePath = function pbjsResolvePath(origin, target) {
var normOrigin = protobuf.util.path.normalize(origin),
normTarget = protobuf.util.path.normalize(target);
if (!normOrigin)
mainFiles.push(normTarget);
var resolved = protobuf.util.path.resolve(normOrigin, normTarget, true);
var idx = resolved.lastIndexOf("google/protobuf/");
if (idx > -1) {
var altname = resolved.substring(idx);
if (altname in protobuf.common)
resolved = altname;
}
if (fs.existsSync(resolved))
return resolved;
for (var i = 0; i < paths.length; ++i) {
var iresolved = protobuf.util.path.resolve(paths[i] + "/", target);
if (fs.existsSync(iresolved))
return iresolved;
}
return resolved;
};
// Use es6 syntax if not explicitly specified on the command line and the es6 wrapper is used
if (argv.wrap === "es6" || argv.es6) {
argv.wrap = "es6";
argv.es6 = true;
}
var parseOptions = {
"keepCase": argv["keep-case"] || false
};
// Read from stdin
if (files.length === 1 && files[0] === "-") {
var data = [];
process.stdin.on("data", function(chunk) {
data.push(chunk);
});
process.stdin.on("end", function() {
var source = Buffer.concat(data).toString("utf8");
try {
if (source.charAt(0) !== "{") {
protobuf.parse.filename = "-";
protobuf.parse(source, root, parseOptions);
} else {
var json = JSON.parse(source);
root.setOptions(json.options).addJSON(json);
}
callTarget();
} catch (err) {
if (callback) {
callback(err);
return;
}
throw err;
}
});
// Load from disk
} else {
try {
root.loadSync(files, parseOptions).resolveAll(); // sync is deterministic while async is not
if (argv.sparse)
sparsify(root);
callTarget();
} catch (err) {
if (callback) {
callback(err);
return undefined;
}
throw err;
}
}
function markReferenced(tobj) {
tobj.referenced = true;
// also mark a type's fields and oneofs
if (tobj.fieldsArray)
tobj.fieldsArray.forEach(function(fobj) {
fobj.referenced = true;
});
if (tobj.oneofsArray)
tobj.oneofsArray.forEach(function(oobj) {
oobj.referenced = true;
});
// also mark an extension field's extended type, but not its (other) fields
if (tobj.extensionField)
tobj.extensionField.parent.referenced = true;
}
function sparsify(root) {
// 1. mark directly or indirectly referenced objects
util.traverse(root, function(obj) {
if (!obj.filename)
return;
if (mainFiles.indexOf(obj.filename) > -1)
util.traverseResolved(obj, markReferenced);
});
// 2. empty unreferenced objects
util.traverse(root, function(obj) {
var parent = obj.parent;
if (!parent || obj.referenced) // root or referenced
return;
// remove unreferenced namespaces
if (obj instanceof protobuf.Namespace) {
var hasReferenced = false;
util.traverse(obj, function(iobj) {
if (iobj.referenced)
hasReferenced = true;
});
if (hasReferenced) { // replace with plain namespace if a namespace subclass
if (obj instanceof protobuf.Type || obj instanceof protobuf.Service) {
var robj = new protobuf.Namespace(obj.name, obj.options);
robj.nested = obj.nested;
parent.add(robj);
}
} else // remove completely if nothing inside is referenced
parent.remove(obj);
// remove everything else unreferenced
} else if (!(obj instanceof protobuf.Namespace))
parent.remove(obj);
});
// 3. validate that everything is fine
root.resolveAll();
}
function callTarget() {
target(root, argv, function targetCallback(err, output) {
if (err) {
if (callback)
return callback(err);
throw err;
}
try {
if (argv.out)
fs.writeFileSync(argv.out, output, { encoding: "utf8" });
else if (!callback)
process.stdout.write(output, "utf8");
return callback
? callback(null, output)
: undefined;
} catch (err) {
if (callback)
return callback(err);
throw err;
}
});
}
return undefined;
};