mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-14 23:41:30 +00:00
Restructure types; Add a use-case specific options parser; Allow (re)creation of specific parser fixtures
This commit is contained in:
196
cli/asc.js
196
cli/asc.js
@ -11,34 +11,30 @@
|
||||
* @module cli/asc
|
||||
*/
|
||||
|
||||
// Use "." instead of "/" as cwd in browsers
|
||||
if (process.browser) process.cwd = function() { return "."; };
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const utf8 = require("@protobufjs/utf8");
|
||||
const colors = require("./util/colors");
|
||||
const colorsUtil = require("./util/colors");
|
||||
const optionsUtil = require("./util/options");
|
||||
const EOL = process.platform === "win32" ? "\r\n" : "\n";
|
||||
|
||||
// Use distribution files if present, otherwise run the sources directly
|
||||
var assemblyscript, isDev;
|
||||
var assemblyscript, isDev = false;
|
||||
(() => {
|
||||
try {
|
||||
assemblyscript = require("../dist/assemblyscript.js");
|
||||
isDev = false;
|
||||
} catch (e) {
|
||||
try {
|
||||
require("ts-node").register({
|
||||
project: path.join(__dirname, "..", "src", "tsconfig.json"),
|
||||
files: [ // see: https://github.com/TypeStrong/ts-node/issues/620
|
||||
path.join(__dirname, "..", "std", "portable.d.ts"),
|
||||
path.join(__dirname, "..", "src", "glue", "binaryen.d.ts")
|
||||
]
|
||||
});
|
||||
require("ts-node").register({ project: path.join(__dirname, "..", "src", "tsconfig.json") });
|
||||
require("../src/glue/js");
|
||||
assemblyscript = require("../src");
|
||||
isDev = true;
|
||||
} catch (e) {
|
||||
// last resort: same directory CommonJS
|
||||
assemblyscript = eval("require('./assemblyscript')");
|
||||
isDev = false;
|
||||
}
|
||||
}
|
||||
})();
|
||||
@ -70,7 +66,7 @@ exports.defaultShrinkLevel = 1;
|
||||
/** Bundled library files. */
|
||||
exports.libraryFiles = exports.isBundle ? BUNDLE_LIBRARY : (() => { // set up if not a bundle
|
||||
const libDir = path.join(__dirname, "..", "std", "assembly");
|
||||
const libFiles = require("glob").sync("**/*.ts", { cwd: libDir });
|
||||
const libFiles = require("glob").sync("**/!(*.d).ts", { cwd: libDir });
|
||||
const bundled = {};
|
||||
libFiles.forEach(file => bundled[file.replace(/\.ts$/, "")] = fs.readFileSync(path.join(libDir, file), "utf8" ));
|
||||
return bundled;
|
||||
@ -80,8 +76,8 @@ exports.libraryFiles = exports.isBundle ? BUNDLE_LIBRARY : (() => { // set up if
|
||||
exports.definitionFiles = exports.isBundle ? BUNDLE_DEFINITIONS : (() => { // set up if not a bundle
|
||||
const stdDir = path.join(__dirname, "..", "std");
|
||||
return {
|
||||
"assembly": fs.readFileSync(path.join(stdDir, "assembly.d.ts"), "utf8"),
|
||||
"portable": fs.readFileSync(path.join(stdDir, "portable.d.ts"), "utf8")
|
||||
"assembly": fs.readFileSync(path.join(stdDir, "assembly", "index.d.ts"), "utf8"),
|
||||
"portable": fs.readFileSync(path.join(stdDir, "portable", "index.d.ts"), "utf8")
|
||||
};
|
||||
})();
|
||||
|
||||
@ -94,12 +90,16 @@ exports.compileString = (sources, options) => {
|
||||
binary: null,
|
||||
text: null
|
||||
});
|
||||
exports.main([
|
||||
var argv = [
|
||||
"--binaryFile", "binary",
|
||||
"--textFile", "text",
|
||||
...Object.keys(options || {}).map(arg => `--${arg}=${options[arg]}`),
|
||||
...Object.keys(sources),
|
||||
], {
|
||||
];
|
||||
Object.keys(options || {}).forEach(key => {
|
||||
var val = options[key];
|
||||
if (Array.isArray(val)) val.forEach(val => argv.push("--" + key, String(val)));
|
||||
else argv.push("--" + key, String(val));
|
||||
});
|
||||
exports.main(argv.concat(Object.keys(sources)), {
|
||||
stdout: output.stdout,
|
||||
stderr: output.stderr,
|
||||
readFile: name => sources.hasOwnProperty(name) ? sources[name] : null,
|
||||
@ -129,22 +129,34 @@ exports.main = function main(argv, options, callback) {
|
||||
if (!stdout) throw Error("'options.stdout' must be specified");
|
||||
if (!stderr) throw Error("'options.stderr' must be specified");
|
||||
|
||||
const args = parseArguments(argv);
|
||||
const indent = 24;
|
||||
|
||||
const opts = optionsUtil.parse(argv, exports.options);
|
||||
const args = opts.options;
|
||||
argv = opts.arguments;
|
||||
if (args.noColors) {
|
||||
colors.stdout.supported =
|
||||
colors.stderr.supported = false;
|
||||
colorsUtil.stdout.supported =
|
||||
colorsUtil.stderr.supported = false;
|
||||
} else {
|
||||
colors.stdout = colors.from(stdout);
|
||||
colors.stderr = colors.from(stderr);
|
||||
colorsUtil.stdout = colorsUtil.from(stdout);
|
||||
colorsUtil.stderr = colorsUtil.from(stderr);
|
||||
}
|
||||
|
||||
// Check for unknown arguments
|
||||
if (opts.unknown.length) {
|
||||
opts.unknown.forEach(arg => {
|
||||
stderr.write(colorsUtil.stderr.yellow("WARN: ") + "Unknown option '" + arg + "'" + EOL);
|
||||
});
|
||||
}
|
||||
|
||||
// Check for trailing arguments
|
||||
if (opts.trailing.length) {
|
||||
stderr.write(colorsUtil.stderr.yellow("WARN: ") + "Unsupported trailing arguments: " + opts.trailing.join(" ") + EOL);
|
||||
}
|
||||
|
||||
// Use default callback if none is provided
|
||||
if (!callback) callback = function defaultCallback(err) {
|
||||
var code = 0;
|
||||
if (err) {
|
||||
stderr.write(colors.stderr.red("ERROR: ") + err.stack.replace(/^ERROR: /i, "") + EOL);
|
||||
stderr.write(colorsUtil.stderr.red("ERROR: ") + err.stack.replace(/^ERROR: /i, "") + EOL);
|
||||
code = 1;
|
||||
}
|
||||
return code;
|
||||
@ -156,43 +168,22 @@ exports.main = function main(argv, options, callback) {
|
||||
return callback(null);
|
||||
}
|
||||
// Print the help message if requested or no source files are provided
|
||||
if (args.help || args._.length < 1) {
|
||||
const opts = [];
|
||||
Object.keys(exports.options).forEach(name => {
|
||||
var option = exports.options[name];
|
||||
var text = " ";
|
||||
text += "--" + name;
|
||||
if (option.aliases && option.aliases[0].length === 1) {
|
||||
text += ", -" + option.aliases[0];
|
||||
}
|
||||
while (text.length < indent) {
|
||||
text += " ";
|
||||
}
|
||||
if (Array.isArray(option.description)) {
|
||||
opts.push(text + option.description[0] + option.description.slice(1).map(line => {
|
||||
for (let i = 0; i < indent; ++i) {
|
||||
line = " " + line;
|
||||
}
|
||||
return EOL + line;
|
||||
}).join(""));
|
||||
} else {
|
||||
opts.push(text + option.description);
|
||||
}
|
||||
});
|
||||
|
||||
if (args.help || !argv.length) {
|
||||
var out = args.help ? stdout : stderr;
|
||||
var color = args.help ? colors.stdout : colors.stderr;
|
||||
var color = args.help ? colorsUtil.stdout : colorsUtil.stderr;
|
||||
out.write([
|
||||
color.white("Syntax"),
|
||||
color.white("SYNTAX"),
|
||||
" " + color.cyan("asc") + " [entryFile ...] [options]",
|
||||
"",
|
||||
color.white("Examples"),
|
||||
color.white("EXAMPLES"),
|
||||
" " + color.cyan("asc") + " hello.ts",
|
||||
" " + color.cyan("asc") + " hello.ts -b hello.wasm -t hello.wat",
|
||||
" " + color.cyan("asc") + " hello1.ts hello2.ts -b -O > hello.wasm",
|
||||
"",
|
||||
color.white("Options"),
|
||||
].concat(opts).join(EOL) + EOL);
|
||||
color.white("OPTIONS"),
|
||||
].concat(
|
||||
optionsUtil.help(exports.options, 24, EOL)
|
||||
).join(EOL) + EOL);
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
@ -209,7 +200,6 @@ exports.main = function main(argv, options, callback) {
|
||||
// Set up transforms
|
||||
const transforms = [];
|
||||
if (args.transform) {
|
||||
if (typeof args.transform === "string") args.transform = args.transform.split(",");
|
||||
args.transform.forEach(transform =>
|
||||
transforms.push(
|
||||
require(
|
||||
@ -246,8 +236,9 @@ exports.main = function main(argv, options, callback) {
|
||||
}
|
||||
const customLibDirs = [];
|
||||
if (args.lib) {
|
||||
if (typeof args.lib === "string") args.lib = args.lib.split(",");
|
||||
Array.prototype.push.apply(customLibDirs, args.lib.map(lib => lib.trim()));
|
||||
let lib = args.lib;
|
||||
if (typeof lib === "string") lib = lib.split(",");
|
||||
Array.prototype.push.apply(customLibDirs, lib.map(lib => lib.trim()));
|
||||
for (let i = 0, k = customLibDirs.length; i < k; ++i) { // custom
|
||||
let libDir = customLibDirs[i];
|
||||
let libFiles;
|
||||
@ -275,10 +266,10 @@ exports.main = function main(argv, options, callback) {
|
||||
}
|
||||
|
||||
// Include entry files
|
||||
for (let i = 0, k = args._.length; i < k; ++i) {
|
||||
const filename = args._[i];
|
||||
for (let i = 0, k = argv.length; i < k; ++i) {
|
||||
const filename = argv[i];
|
||||
|
||||
let sourcePath = filename.replace(/\\/g, "/").replace(/(\.ts|\/)$/, "");
|
||||
let sourcePath = String(filename).replace(/\\/g, "/").replace(/(\.ts|\/)$/, "");
|
||||
|
||||
// Try entryPath.ts, then entryPath/index.ts
|
||||
let sourceText = readFile(path.join(baseDir, sourcePath) + ".ts");
|
||||
@ -385,51 +376,28 @@ exports.main = function main(argv, options, callback) {
|
||||
const program = assemblyscript.finishParsing(parser);
|
||||
|
||||
// Set up optimization levels
|
||||
var optimizeLevel = -1;
|
||||
var optimizeLevel = 0;
|
||||
var shrinkLevel = 0;
|
||||
var debugInfo = !args.noDebug;
|
||||
if (args.optimize !== false) {
|
||||
if (typeof args.optimize === "number") {
|
||||
optimizeLevel = args.optimize;
|
||||
} else if (args["0"]) {
|
||||
optimizeLevel = 0;
|
||||
} else if (args["1"]) {
|
||||
optimizeLevel = 1;
|
||||
} else if (args["2"]) {
|
||||
optimizeLevel = 2;
|
||||
} else if (args["3"]) {
|
||||
optimizeLevel = 3;
|
||||
} else if (args.optimize === true) {
|
||||
optimizeLevel = exports.defaultOptimizeLevel;
|
||||
shrinkLevel = exports.defaultShrinkLevel;
|
||||
} else
|
||||
optimizeLevel = 0;
|
||||
}
|
||||
if (args["s"]) {
|
||||
shrinkLevel = 1;
|
||||
} else if (args["z"]) {
|
||||
shrinkLevel = 2;
|
||||
if (args.optimize) {
|
||||
optimizeLevel = exports.defaultOptimizeLevel;
|
||||
shrinkLevel = exports.defaultShrinkLevel;
|
||||
}
|
||||
if (typeof args.optimizeLevel === "number") {
|
||||
optimizeLevel = args.optimizeLevel;
|
||||
}
|
||||
if (typeof args.shrinkLevel === "number") {
|
||||
shrinkLevel = args.shrinkLevel;
|
||||
} else if (args.shrinkLevel === "s") {
|
||||
shrinkLevel = 1;
|
||||
} else if (args.shrinkLevel === "z") {
|
||||
shrinkLevel = 2;
|
||||
}
|
||||
optimizeLevel = Math.max(optimizeLevel, 0);
|
||||
shrinkLevel = Math.max(shrinkLevel, 0);
|
||||
optimizeLevel = Math.min(Math.max(optimizeLevel, 0), 3);
|
||||
shrinkLevel = Math.min(Math.max(shrinkLevel, 0), 2);
|
||||
|
||||
// Begin compilation
|
||||
const compilerOptions = assemblyscript.createOptions();
|
||||
assemblyscript.setTarget(compilerOptions, 0);
|
||||
assemblyscript.setNoTreeShaking(compilerOptions, !!args.noTreeShaking);
|
||||
assemblyscript.setNoAssert(compilerOptions, !!args.noAssert);
|
||||
assemblyscript.setImportMemory(compilerOptions, !!args.importMemory);
|
||||
assemblyscript.setImportTable(compilerOptions, !!args.importTable);
|
||||
assemblyscript.setNoTreeShaking(compilerOptions, args.noTreeShaking);
|
||||
assemblyscript.setNoAssert(compilerOptions, args.noAssert);
|
||||
assemblyscript.setImportMemory(compilerOptions, args.importMemory);
|
||||
assemblyscript.setImportTable(compilerOptions, args.importTable);
|
||||
assemblyscript.setMemoryBase(compilerOptions, args.memoryBase >>> 0);
|
||||
assemblyscript.setSourceMap(compilerOptions, args.sourceMap != null);
|
||||
assemblyscript.setOptimizeLevelHints(compilerOptions, optimizeLevel, shrinkLevel);
|
||||
@ -515,7 +483,7 @@ exports.main = function main(argv, options, callback) {
|
||||
|
||||
module.setOptimizeLevel(optimizeLevel);
|
||||
module.setShrinkLevel(shrinkLevel);
|
||||
module.setDebugInfo(debugInfo);
|
||||
module.setDebugInfo(!args.noDebug);
|
||||
|
||||
var runPasses = [];
|
||||
if (args.runPasses) {
|
||||
@ -741,7 +709,7 @@ exports.main = function main(argv, options, callback) {
|
||||
var files;
|
||||
try {
|
||||
stats.readTime += measure(() => {
|
||||
files = require("glob").sync("*.ts", { cwd: dirname });
|
||||
files = require("glob").sync("!(*.d).ts", { cwd: dirname });
|
||||
});
|
||||
return files;
|
||||
} catch (e) {
|
||||
@ -764,25 +732,23 @@ exports.main = function main(argv, options, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Parses the specified command line arguments. */
|
||||
function parseArguments(argv) {
|
||||
const opts = {};
|
||||
Object.keys(exports.options).forEach(key => {
|
||||
const opt = exports.options[key];
|
||||
if (opt.aliases) {
|
||||
(opts.alias || (opts.alias = {}))[key] = opt.aliases;
|
||||
}
|
||||
if (opt.default !== undefined) {
|
||||
(opts.default || (opts.default = {}))[key] = opt.default;
|
||||
}
|
||||
if (opt.type === "string") {
|
||||
(opts.string || (opts.string = [])).push(key);
|
||||
} else if (opt.type === "boolean") {
|
||||
(opts.boolean || (opts.boolean = [])).push(key);
|
||||
}
|
||||
});
|
||||
return require("minimist")(argv, opts);
|
||||
}
|
||||
var argumentSubstitutions = {
|
||||
"-O" : [ "--optimize" ],
|
||||
"-Os" : [ "--optimize", "--shrinkLevel", "1" ],
|
||||
"-Oz" : [ "--optimize", "--shrinkLevel", "2" ],
|
||||
"-O0" : [ "--optimizeLevel", "0", "--shrinkLevel", "0" ],
|
||||
"-O0s": [ "--optimizeLevel", "0", "--shrinkLevel", "1" ],
|
||||
"-O0z": [ "--optimizeLevel", "0", "--shrinkLevel", "2" ],
|
||||
"-O1" : [ "--optimizeLevel", "1", "--shrinkLevel", "0" ],
|
||||
"-O1s": [ "--optimizeLevel", "1", "--shrinkLevel", "1" ],
|
||||
"-O1z": [ "--optimizeLevel", "1", "--shrinkLevel", "2" ],
|
||||
"-O2" : [ "--optimizeLevel", "2", "--shrinkLevel", "0" ],
|
||||
"-O2s": [ "--optimizeLevel", "2", "--shrinkLevel", "1" ],
|
||||
"-O2z": [ "--optimizeLevel", "2", "--shrinkLevel", "2" ],
|
||||
"-O3" : [ "--optimizeLevel", "3", "--shrinkLevel", "0" ],
|
||||
"-O3s": [ "--optimizeLevel", "3", "--shrinkLevel", "1" ],
|
||||
"-O3z": [ "--optimizeLevel", "3", "--shrinkLevel", "2" ],
|
||||
};
|
||||
|
||||
/** Checks diagnostics emitted so far for errors. */
|
||||
function checkDiagnostics(emitter, stderr) {
|
||||
|
113
cli/asc.json
113
cli/asc.json
@ -1,17 +1,17 @@
|
||||
{
|
||||
"version": {
|
||||
"description": "Prints just the compiler's version and exits.",
|
||||
"type": "boolean",
|
||||
"aliases": [ "v" ]
|
||||
"type": "b",
|
||||
"alias": "v"
|
||||
},
|
||||
"help": {
|
||||
"description": "Prints this message and exits.",
|
||||
"type": "boolean",
|
||||
"aliases": [ "h" ]
|
||||
"type": "b",
|
||||
"alias": "h"
|
||||
},
|
||||
"optimize": {
|
||||
"description": [
|
||||
"Optimizes the module. Also accepts the optimize level:",
|
||||
"Optimizes the module. Also has the usual shorthands:",
|
||||
"",
|
||||
" -O Uses defaults. Equivalent to -O2s",
|
||||
" -O0 Equivalent to --optimizeLevel 0",
|
||||
@ -22,109 +22,119 @@
|
||||
" -O3s Equivalent to -O3 with --shrinkLevel 1 etc.",
|
||||
""
|
||||
],
|
||||
"type": "boolean",
|
||||
"aliases": [ "O" ]
|
||||
"type": "b",
|
||||
"alias": "O"
|
||||
},
|
||||
"optimizeLevel": {
|
||||
"description": "How much to focus on optimizing code. [0-3]",
|
||||
"type": "number"
|
||||
"type": "i"
|
||||
},
|
||||
"shrinkLevel": {
|
||||
"description": "How much to focus on shrinking code size. [0-2, s=1, z=2]",
|
||||
"type": "number"
|
||||
"type": "i"
|
||||
},
|
||||
"validate": {
|
||||
"description": "Validates the module using Binaryen. Exits if invalid.",
|
||||
"type": "boolean",
|
||||
"aliases": [ "c", "check" ]
|
||||
"type": "b",
|
||||
"alias": "c",
|
||||
"default": false
|
||||
},
|
||||
"baseDir": {
|
||||
"description": "Specifies the base directory of input and output files.",
|
||||
"type": "string"
|
||||
"type": "s",
|
||||
"default": "."
|
||||
},
|
||||
"outFile": {
|
||||
"description": "Specifies the output file. File extension indicates format.",
|
||||
"type": "string",
|
||||
"aliases": [ "o" ]
|
||||
"type": "s",
|
||||
"alias": "o"
|
||||
},
|
||||
"binaryFile": {
|
||||
"description": "Specifies the binary output file (.wasm).",
|
||||
"type": "string",
|
||||
"aliases": [ "b" ]
|
||||
"type": "s",
|
||||
"alias": "b"
|
||||
},
|
||||
"textFile": {
|
||||
"description": "Specifies the text output file (.wat).",
|
||||
"type": "string",
|
||||
"aliases": [ "t" ]
|
||||
"type": "s",
|
||||
"alias": "t"
|
||||
},
|
||||
"asmjsFile": {
|
||||
"description": "Specifies the asm.js output file (.js).",
|
||||
"type": "string",
|
||||
"aliases": [ "a" ]
|
||||
"type": "s",
|
||||
"alias": "a"
|
||||
},
|
||||
"idlFile": {
|
||||
"description": "Specifies the WebIDL output file (.webidl).",
|
||||
"type": "string",
|
||||
"aliases": [ "i" ]
|
||||
"type": "s",
|
||||
"alias": "i"
|
||||
},
|
||||
"tsdFile": {
|
||||
"description": "Specifies the TypeScript definition output file (.d.ts).",
|
||||
"type": "string",
|
||||
"aliases": [ "d", "dtsFile" ]
|
||||
"type": "s",
|
||||
"alias": "d"
|
||||
},
|
||||
"sourceMap": {
|
||||
"description": [
|
||||
"Enables source map generation. Optionally takes the URL",
|
||||
"used to reference the source map from the binary file."
|
||||
],
|
||||
"type": "string"
|
||||
"type": "s"
|
||||
},
|
||||
"noTreeShaking": {
|
||||
"description": "Disables compiler-level tree-shaking, compiling everything.",
|
||||
"type": "boolean"
|
||||
"type": "b",
|
||||
"default": false
|
||||
},
|
||||
"noDebug": {
|
||||
"description": "Disables maintaining of debug information in binaries.",
|
||||
"type": "boolean"
|
||||
"type": "b",
|
||||
"default": false
|
||||
},
|
||||
"noAssert": {
|
||||
"description": "Replaces assertions with just their value without trapping.",
|
||||
"type": "boolean"
|
||||
"type": "b",
|
||||
"default": false
|
||||
},
|
||||
"noEmit": {
|
||||
"description": "Performs compilation as usual but does not emit code.",
|
||||
"type": "boolean"
|
||||
"type": "b",
|
||||
"default": false
|
||||
},
|
||||
"importMemory": {
|
||||
"description": "Imports the memory instance provided by the embedder.",
|
||||
"type": "boolean"
|
||||
"type": "b",
|
||||
"default": false
|
||||
},
|
||||
"memoryBase": {
|
||||
"description": "Sets the start offset of compiler-generated static memory.",
|
||||
"type": "number"
|
||||
"type": "i",
|
||||
"default": 0
|
||||
},
|
||||
"importTable": {
|
||||
"description": "Imports the function table instance provided by the embedder.",
|
||||
"type": "boolean"
|
||||
"type": "b",
|
||||
"default": false
|
||||
},
|
||||
"noLib": {
|
||||
"description": "Does not include the shipped standard library.",
|
||||
"type": "boolean"
|
||||
"type": "b",
|
||||
"default": false
|
||||
},
|
||||
"lib": {
|
||||
"description": [
|
||||
"Adds one or multiple paths to custom library components and",
|
||||
"uses exports of all top-level files at this path as globals."
|
||||
],
|
||||
"type": "string"
|
||||
"type": "s"
|
||||
},
|
||||
"use": {
|
||||
"description": [
|
||||
"Aliases a global object under another name, e.g., to switch",
|
||||
"the default 'Math' implementation used: --use Math=JSMath"
|
||||
],
|
||||
"type": "string",
|
||||
"aliases": [ "u" ]
|
||||
"type": "s",
|
||||
"alias": "u"
|
||||
},
|
||||
"trapMode": {
|
||||
"description": [
|
||||
@ -135,7 +145,7 @@
|
||||
" js Replace trapping operations with JS semantics.",
|
||||
""
|
||||
],
|
||||
"type": "string",
|
||||
"type": "s",
|
||||
"default": "allow"
|
||||
},
|
||||
"runPasses": {
|
||||
@ -143,7 +153,7 @@
|
||||
"Specifies additional Binaryen passes to run after other",
|
||||
"optimizations, if any. See: Binaryen/src/passes/pass.cpp"
|
||||
],
|
||||
"type": "string"
|
||||
"type": "s"
|
||||
},
|
||||
"enable": {
|
||||
"description": [
|
||||
@ -153,19 +163,34 @@
|
||||
" mutable-global Enables mutable global imports and exports",
|
||||
""
|
||||
],
|
||||
"type": "string",
|
||||
"aliases": [ "feature" ]
|
||||
"type": "s"
|
||||
},
|
||||
"transform": {
|
||||
"description": "Specifies the path to a custom transform to 'require'.",
|
||||
"type": "string"
|
||||
"type": "S"
|
||||
},
|
||||
"measure": {
|
||||
"description": "Prints measuring information on I/O and compile times.",
|
||||
"type": "boolean"
|
||||
"type": "b",
|
||||
"default": false
|
||||
},
|
||||
"noColors": {
|
||||
"description": "Disables terminal colors.",
|
||||
"type": "boolean"
|
||||
}
|
||||
"type": "b",
|
||||
"default": false
|
||||
},
|
||||
"-Os": { "value": { "optimize": true, "shrinkLevel": 1 } },
|
||||
"-Oz": { "value": { "optimize": true, "shrinkLevel": 2 } },
|
||||
"-O0": { "value": { "optimizeLevel": 0, "shrinkLevel": 0 } },
|
||||
"-O1": { "value": { "optimizeLevel": 1, "shrinkLevel": 0 } },
|
||||
"-O2": { "value": { "optimizeLevel": 2, "shrinkLevel": 0 } },
|
||||
"-O3": { "value": { "optimizeLevel": 3, "shrinkLevel": 0 } },
|
||||
"-O0s": { "value": { "optimizeLevel": 0, "shrinkLevel": 1 } },
|
||||
"-O1s": { "value": { "optimizeLevel": 1, "shrinkLevel": 1 } },
|
||||
"-O2s": { "value": { "optimizeLevel": 2, "shrinkLevel": 1 } },
|
||||
"-O3s": { "value": { "optimizeLevel": 3, "shrinkLevel": 1 } },
|
||||
"-O0z": { "value": { "optimizeLevel": 0, "shrinkLevel": 2 } },
|
||||
"-O1z": { "value": { "optimizeLevel": 1, "shrinkLevel": 2 } },
|
||||
"-O2z": { "value": { "optimizeLevel": 2, "shrinkLevel": 2 } },
|
||||
"-O3z": { "value": { "optimizeLevel": 3, "shrinkLevel": 2 } }
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
var proc = typeof process !== "undefined" && process || {};
|
||||
var isCI = proc.env && "CI" in proc.env;
|
||||
var isCI = proc.env && "CI" in proc.env; // doesn't work when bundled because 'process' is a mock
|
||||
|
||||
function from(stream, base) {
|
||||
var colors = base || {};
|
||||
|
41
cli/util/options.d.ts
vendored
Normal file
41
cli/util/options.d.ts
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
/** Configuration object. */
|
||||
interface Config {
|
||||
[key: string]: {
|
||||
/** Textual description. */
|
||||
description?: string | string[],
|
||||
/** Data type. One of (b)oolean [default], (i)nteger, (f)loat or (s)tring. Uppercase means multiple values. */
|
||||
type?: "b" | "i" | "f" | "s", "I", "F", "S",
|
||||
/** Substituted options, if any. */
|
||||
value?: { [key: string]: number | string },
|
||||
/** Short alias, if any. */
|
||||
alias?: string
|
||||
};
|
||||
}
|
||||
|
||||
/** Parsing result. */
|
||||
interface Result {
|
||||
/** Parsed options. */
|
||||
options: { [key: string]: number | string },
|
||||
/** Unknown options. */
|
||||
unknown: string[],
|
||||
/** Normal arguments. */
|
||||
arguments: string[],
|
||||
/** Trailing arguments. */
|
||||
trailing: string[]
|
||||
}
|
||||
|
||||
/** Parses the specified command line arguments according to the given configuration. */
|
||||
export function parse(argv: string[], config: Config): Result;
|
||||
|
||||
/** Help formatting options. */
|
||||
interface HelpOptions {
|
||||
/** Leading indent. Defaults to 2. */
|
||||
indent?: number,
|
||||
/** Table padding. Defaults to 24. */
|
||||
padding?: number,
|
||||
/** End of line character. Defaults to "\n". */
|
||||
eol?: string
|
||||
}
|
||||
|
||||
/** Generates the help text for the specified configuration. */
|
||||
export function help(config: Config, options?: HelpOptions): string;
|
105
cli/util/options.js
Normal file
105
cli/util/options.js
Normal file
@ -0,0 +1,105 @@
|
||||
// type | meaning
|
||||
// -----|---------------
|
||||
// b | boolean
|
||||
// i | integer
|
||||
// f | float
|
||||
// s | string
|
||||
// I | integer array
|
||||
// F | float array
|
||||
// S | string array
|
||||
|
||||
/** Parses the specified command line arguments according to the given configuration. */
|
||||
function parse(argv, config) {
|
||||
var options = {};
|
||||
var unknown = [];
|
||||
var arguments = [];
|
||||
var trailing = [];
|
||||
|
||||
// make an alias map and initialize defaults
|
||||
var aliases = {};
|
||||
Object.keys(config).forEach(key => {
|
||||
var option = config[key];
|
||||
if (option.alias != null) {
|
||||
if (typeof option.alias === "string") aliases[option.alias] = key;
|
||||
else if (Array.isArray(option.alias)) option.alias.forEach(alias => aliases[alias] = key);
|
||||
}
|
||||
if (option.default != null) options[key] = option.default;
|
||||
});
|
||||
|
||||
// iterate over argv
|
||||
for (var i = 0, k = (argv = argv.slice()).length; i < k; ++i) {
|
||||
let arg = argv[i];
|
||||
if (arg == "--") { ++i; break; }
|
||||
let match = /^(?:(\-\w)|(\-\-\w{2,})(?:=(.*))?)$/.exec(arg), option, key;
|
||||
if (match) {
|
||||
if (config[arg]) option = config[key = arg]; // exact
|
||||
else if (match[1] != null) option = config[key = aliases[match[1].substring(1)]]; // alias
|
||||
else if (match[2] != null) {
|
||||
option = config[key = match[2].substring(2)]; // full
|
||||
if (option && match[3] != null) argv[i--] = match[3];
|
||||
}
|
||||
} else {
|
||||
if (arg.charCodeAt(0) == 45) option = config[key = arg]; // exact
|
||||
else { arguments.push(arg); continue; } // argument
|
||||
}
|
||||
if (option) {
|
||||
if (option.type == null || option.type === "b") options[key] = true; // flag
|
||||
else {
|
||||
if (i + 1 < argv.length && argv[i + 1].charCodeAt(0) != 45) { // present
|
||||
switch (option.type) {
|
||||
case "i": options[key] = parseInt(argv[++i], 10); break;
|
||||
case "I": options[key] = (options[key] || []).concat(parseInt(argv[++i], 10)); break;
|
||||
case "f": options[key] = parseFloat(argv[++i]); break;
|
||||
case "F": options[key] = (options[key] || []).concat(parseFloat(argv[++i])); break;
|
||||
case "s": options[key] = String(argv[++i]); break;
|
||||
case "S": options[key] = (options[key] || []).concat(argv[++i].split(",")); break;
|
||||
default: unknown.push(arg); --i;
|
||||
}
|
||||
} else { // omitted
|
||||
switch (option.type) {
|
||||
case "i":
|
||||
case "f": options[key] = option.default || 0; break;
|
||||
case "s": options[key] = option.default || ""; break;
|
||||
case "I":
|
||||
case "F":
|
||||
case "S": options[key] = options.default || []; break;
|
||||
default: unknown.push(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (option.value) Object.keys(option.value).forEach(k => options[k] = option.value[k]);
|
||||
} else unknown.push(arg);
|
||||
}
|
||||
while (i < k) trailing.push(argv[i++]); // trailing
|
||||
|
||||
return { options, unknown, arguments, trailing };
|
||||
}
|
||||
|
||||
exports.parse = parse;
|
||||
|
||||
/** Generates the help text for the specified configuration. */
|
||||
function help(config, options) {
|
||||
if (!options) options = {};
|
||||
var indent = options.indent || 2;
|
||||
var padding = options.padding || 24;
|
||||
var eol = options.eol || "\n";
|
||||
var sb = [];
|
||||
Object.keys(config).forEach(key => {
|
||||
var option = config[key];
|
||||
if (option.description == null) return;
|
||||
var text = "";
|
||||
while (text.length < indent) text += " ";
|
||||
text += "--" + key;
|
||||
if (option.alias) text += ", -" + option.alias;
|
||||
while (text.length < padding) text += " ";
|
||||
if (Array.isArray(option.description)) {
|
||||
sb.push(text + option.description[0] + option.description.slice(1).map(line => {
|
||||
for (let i = 0; i < padding; ++i) line = " " + line;
|
||||
return eol + line;
|
||||
}).join(""));
|
||||
} else sb.push(text + option.description);
|
||||
});
|
||||
return sb.join(eol);
|
||||
}
|
||||
|
||||
exports.help = help;
|
Reference in New Issue
Block a user