2020-05-19 11:43:42 +03:00

197 lines
5.8 KiB
JavaScript

// ng-annotate.js
// MIT licensed, see LICENSE file
// Copyright (c) 2013-2016 Olov Lassus <olov.lassus@gmail.com>
"use strict";
const t0 = Date.now();
const fs = require("fs");
const commander = require("commander");
const ngAnnotate = require("./ng-annotate-main");
const version = require("../package.json").version;
const program = new commander.Command()
.version(version)
.usage(
"OPTIONS <file>\n\n" +
"provide - instead of <file> to read from stdin\n" +
"use -a and -r together to remove and add (rebuild) annotations in one go"
)
.option("-a, --add", "add dependency injection annotations where non-existing")
.option("-r, --remove", "remove all existing dependency injection annotations")
.option("-o <file>", "write output to <file>. output is written to stdout by default")
.option("--sourcemap", "generate an inline sourcemap")
.option("--sourceroot <sourceRoot>", "set the sourceRoot property of the generated sourcemap")
.option("--single_quotes", "use single quotes (') instead of double quotes (\")")
.option("--regexp <regexp>", "detect short form myMod.controller(...) iff myMod matches regexp")
.option("--rename <to>", "rename declarations and annotated references\noldname1 newname1 oldname2 newname2 ...", "")
.option("--plugin <plugin>", "use plugin with path (experimental)")
.option("--enable <name>", "enable optional with name")
.option("--list", "list all optional names")
.option("--stats", "print statistics on stderr (experimental)")
.parse(process.argv);
function exit(msg) {
if (msg) {
process.stderr.write(msg);
process.stderr.write("\n");
}
process.exit(-1);
}
// special-case for --list
if (program.list) {
const list = ngAnnotate("", {list: true}).list;
if (list.length >= 1) {
process.stdout.write(list.join("\n") + "\n");
}
process.exit(0);
}
// validate options
if (program.args.length !== 1) {
program.outputHelp();
exit("error: no input file provided");
}
if (!program.add && !program.remove) {
program.outputHelp();
exit("error: missing option --add and/or --remove");
}
const filename = program.args.shift();
(filename === "-" ? slurpStdin : slurpFile)(runAnnotate);
function slurpStdin(cb) {
let buf = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", function(d) {
buf += d;
});
process.stdin.on("end", function() {
cb(null, buf);
});
process.stdin.resume();
}
function slurpFile(cb) {
if (!fs.existsSync(filename)) {
cb(new Error(`error: file not found ${filename}`));
}
fs.readFile(filename, cb);
}
function runAnnotate(err, src) {
if (err) {
exit(err.message);
}
src = String(src);
let config;
try {
config = JSON.parse(String(fs.readFileSync("ng-annotate-config.json")));
} catch (e) {
config = {};
}
if (filename !== "-") {
config.inFile = filename;
}
["add", "remove", "o", "regexp", "rename", "single_quotes", "plugin", "enable", "stats"].forEach(function(opt) {
if (opt in program) {
config[opt] = program[opt];
}
});
if (program.sourcemap) {
config.map = { inline: true, sourceRoot: program.sourceroot };
if (filename !== "-") {
config.map.inFile = filename;
}
};
if (config.enable && !Array.isArray(config.enable)) {
config.enable = [config.enable];
}
if (config.plugin) {
if (!Array.isArray(config.plugin)) {
config.plugin = [config.plugin];
}
config.plugin = config.plugin.map(function(path) {
let absPath;
try {
absPath = fs.realpathSync.bind(fs, path);
} catch (e) {
absPath = null;
}
if (!absPath) {
exit(`error: plugin file not found ${path}`);
}
// the require below may throw an exception on parse-error
try {
return require(absPath);
} catch (e) {
// node will already print file:line and offending line to stderr
exit(`error: couldn't require("${absPath}")`);
}
});
}
const trimmedRename = config.rename && config.rename.trim();
if (trimmedRename) {
const flattenRename = trimmedRename.split(" ");
const renameArray = [];
for (let i = 0; i < flattenRename.length; i = i + 2) {
renameArray.push({
"from": flattenRename[i],
"to": flattenRename[i + 1],
});
}
config.rename = renameArray;
} else {
config.rename = null;
}
const run_t0 = Date.now();
const ret = ngAnnotate(src, config);
const run_t1 = Date.now();
if (ret.errors) {
exit(ret.errors.join("\n"));
}
const stats = ret._stats;
if (config.stats && stats) {
const t1 = Date.now();
const all = t1 - t0;
const run_parser = stats.parser_parse_t1 - stats.parser_parse_t0;
const all_parser = run_parser + (stats.parser_require_t1 - stats.parser_require_t0);
const nga_run = (run_t1 - run_t0) - run_parser;
const nga_init = all - all_parser - nga_run;
const pct = function(n) {
return Math.round(100 * n / all);
}
process.stderr.write(`[${all} ms] parser: ${all_parser}, nga init: ${nga_init}, nga run: ${nga_run}\n`);
process.stderr.write(`[%] parser: ${pct(all_parser)}, nga init: ${pct(nga_init)}, nga run: ${pct(nga_run)}\n`);
}
if (ret.src && config.o) {
try {
fs.writeFileSync(config.o, ret.src);
} catch (e) {
exit(e.message);
}
} else if (ret.src) {
process.stdout.write(ret.src);
}
}