--- /dev/null
+"use strict";
+var child_process = require("child_process"),
+ path = require("path"),
+ fs = require("fs"),
+ pkg = require("./package.json"),
+ util = require("./util");
+
+util.setup();
+
+var minimist = require("minimist"),
+ chalk = require("chalk"),
+ glob = require("glob"),
+ tmp = require("tmp");
+
+/**
+ * Runs pbts 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(args, callback) {
+ var argv = minimist(args, {
+ alias: {
+ name: "n",
+ out : "o",
+ main: "m",
+ global: "g",
+ import: "i"
+ },
+ string: [ "name", "out", "global", "import" ],
+ boolean: [ "comments", "main" ],
+ default: {
+ comments: true,
+ main: false
+ }
+ });
+
+ var files = argv._;
+
+ if (!files.length) {
+ if (callback)
+ callback(Error("usage")); // eslint-disable-line callback-return
+ else
+ process.stderr.write([
+ "protobuf.js v" + pkg.version + " CLI for TypeScript",
+ "",
+ chalk.bold.white("Generates TypeScript definitions from annotated JavaScript files."),
+ "",
+ " -o, --out Saves to a file instead of writing to stdout.",
+ "",
+ " -g, --global Name of the global object in browser environments, if any.",
+ "",
+ " -i, --import Comma delimited list of imports. Local names will equal camelCase of the basename.",
+ "",
+ " --no-comments Does not output any JSDoc comments.",
+ "",
+ chalk.bold.gray(" Internal flags:"),
+ "",
+ " -n, --name Wraps everything in a module of the specified name.",
+ "",
+ " -m, --main Whether building the main library without any imports.",
+ "",
+ "usage: " + chalk.bold.green("pbts") + " [options] file1.js file2.js ..." + chalk.bold.gray(" (or) ") + "other | " + chalk.bold.green("pbts") + " [options] -",
+ ""
+ ].join("\n"));
+ return 1;
+ }
+
+ // 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;
+ }
+
+ var cleanup = [];
+
+ // Read from stdin (to a temporary file)
+ if (files.length === 1 && files[0] === "-") {
+ var data = [];
+ process.stdin.on("data", function(chunk) {
+ data.push(chunk);
+ });
+ process.stdin.on("end", function() {
+ files[0] = tmp.tmpNameSync() + ".js";
+ fs.writeFileSync(files[0], Buffer.concat(data));
+ cleanup.push(files[0]);
+ callJsdoc();
+ });
+
+ // Load from disk
+ } else {
+ callJsdoc();
+ }
+
+ function callJsdoc() {
+
+ // There is no proper API for jsdoc, so this executes the CLI and pipes the output
+ var basedir = path.join(__dirname, ".");
+ var moduleName = argv.name || "null";
+ var nodePath = process.execPath;
+ var cmd = "\"" + nodePath + "\" \"" + require.resolve("jsdoc/jsdoc.js") + "\" -c \"" + path.join(basedir, "lib", "tsd-jsdoc.json") + "\" -q \"module=" + encodeURIComponent(moduleName) + "&comments=" + Boolean(argv.comments) + "\" " + files.map(function(file) { return "\"" + file + "\""; }).join(" ");
+ var child = child_process.exec(cmd, {
+ cwd: process.cwd(),
+ argv0: "node",
+ stdio: "pipe",
+ maxBuffer: 1 << 24 // 16mb
+ });
+ var out = [];
+ var ended = false;
+ var closed = false;
+ child.stdout.on("data", function(data) {
+ out.push(data);
+ });
+ child.stdout.on("end", function() {
+ if (closed) finish();
+ else ended = true;
+ });
+ child.stderr.pipe(process.stderr);
+ child.on("close", function(code) {
+ // clean up temporary files, no matter what
+ try { cleanup.forEach(fs.unlinkSync); } catch(e) {/**/} cleanup = [];
+
+ if (code) {
+ out = out.join("").replace(/\s*JSDoc \d+\.\d+\.\d+ [^$]+/, "");
+ process.stderr.write(out);
+ var err = Error("code " + code);
+ if (callback)
+ return callback(err);
+ throw err;
+ }
+
+ if (ended) return finish();
+ closed = true;
+ return undefined;
+ });
+
+ function getImportName(importItem) {
+ return path.basename(importItem, ".js").replace(/([-_~.+]\w)/g, function(match) {
+ return match[1].toUpperCase();
+ });
+ }
+
+ function finish() {
+ var output = [];
+ if (argv.main)
+ output.push(
+ "// DO NOT EDIT! This is a generated file. Edit the JSDoc in src/*.js instead and run 'npm run types'.",
+ ""
+ );
+ if (argv.global)
+ output.push(
+ "export as namespace " + argv.global + ";",
+ ""
+ );
+
+ if (!argv.main) {
+ // Ensure we have a usable array of imports
+ var importArray = typeof argv.import === "string" ? argv.import.split(",") : argv.import || [];
+
+ // Build an object of imports and paths
+ var imports = {
+ $protobuf: "protobufjs"
+ };
+ importArray.forEach(function(importItem) {
+ imports[getImportName(importItem)] = importItem;
+ });
+
+ // Write out the imports
+ Object.keys(imports).forEach(function(key) {
+ output.push("import * as " + key + " from \"" + imports[key] + "\";");
+ });
+ }
+
+ output = output.join("\n") + "\n" + out.join("");
+
+ 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;
+};