UNPKG

fable-compiler-netcore

Version:
219 lines (218 loc) 8.55 kB
"use strict"; var path = require("path"); var child_process = require("child_process"); var fableLib = require("./lib"); var constants = require("./constants"); var bundle_1 = require("./bundle"); var watch_1 = require("./watch"); var options_1 = require("./options"); /** Processes a JSON received from .NET process. If it's a Babel AST it will be compiled. */ function processJson(json, opts, continuation) { try { var babelAst = void 0; try { babelAst = JSON.parse(json); } catch (_err) { return null; // If stdout is not in JSON format, just ignore } if (babelAst.type == "LOG") { if (babelAst.message.indexOf("[WARNING]") == 0) { fableLib.stdoutLog(babelAst.message.replace("[WARNING]", "").trim()); } else if (opts.verbose) { fableLib.stdoutLog(babelAst.message); } } else if (babelAst.type == "ERROR") { throw babelAst; } else if (opts.rollup) { return fableLib.babelify(babelAst, opts); } else { fableLib.babelifyToFile(babelAst, opts); } } catch (err) { fableLib.stderrLog(err); if (!opts.watch) { fableLib.finish(1, continuation); } } return null; } /** Runs the postbuild script and starts watching if necessary */ function postbuild(opts, buildResult, fableProc, continuation) { var parallelProc = null; // The "postbuild-once" script must be run only once (well done, Captain Obvious) // and it musn't wait till the process is finished, as it's normally used // to fire up watch mode of bundlers (Webpack, Rollup...) if (buildResult === "SUCCESS" && opts.scripts && opts.scripts["postbuild-once"]) { var postbuildScript = opts.scripts["postbuild-once"]; delete opts.scripts["postbuild-once"]; parallelProc = fableLib.runCommandInParallel(opts.workingDir, postbuildScript); } // If present, run "postbuild" script after every build and wait till it's finished // to exit the process or start watch mode if (buildResult === "SUCCESS" && opts.scripts && opts.scripts.postbuild) { var continuation2 = function (exitCode) { if (!opts.watch) { fableLib.finish(exitCode, continuation); } else { watch_1.watch(opts, buildResult, fableProc, parallelProc, continuation); } }; fableLib.runCommand(opts.workingDir, opts.scripts.postbuild) .then(continuation2, continuation2); } else if (!opts.watch) { fableLib.finish(buildResult === "SUCCESS" ? 0 : 1, continuation); } else { watch_1.watch(opts, buildResult, fableProc, parallelProc, continuation); } } exports.postbuild = postbuild; /** Builds the project, requires child_process */ function build(opts, continuation) { function wrapInQuotes(arg) { if (process.platform === "win32") { arg = arg.toString().trim(); return arg.indexOf(" ") > 0 && arg[0] != '"' ? '"' + arg + '"' : arg; } else { return arg; } } ; var fableBin = path.resolve(__dirname, "bin/Fable.Client.Node.exe"); if (constants.PKG_NAME === "fable-compiler-netcore") { fableBin = fableBin.replace(".exe", ".dll"); } var fableCmd, fableCmdArgs = [wrapInQuotes(fableBin)]; if (constants.PKG_NAME === "fable-compiler-netcore") { fableCmd = "dotnet"; } else { fableCmd = process.platform === "win32" ? null : "mono"; } for (var k in opts) { if (constants.FABLE_BIN_OPTIONS.has(k)) { if (k === "watch" || k === "rollup") fableCmdArgs.push("--" + k, String(!!opts[k])); // Cast to boolean else if (Array.isArray(opts[k])) opts[k].forEach(function (v) { return fableCmdArgs.push("--" + k, wrapInQuotes(v)); }); else if (typeof opts[k] === "object") Object.getOwnPropertyNames(opts[k]).forEach(function (k2) { return fableCmdArgs.push("--" + k, wrapInQuotes(k2 + "=" + opts[k][k2])); }); else fableCmdArgs.push("--" + k, wrapInQuotes(opts[k])); } } if (process.platform === "win32") { if (fableCmd) { fableCmdArgs.splice(0, 0, fableCmd); } fableCmd = "cmd"; fableCmdArgs = ["/S", "/C", '"' + fableCmdArgs.join(" ") + '"']; } // Call Fable.exe if (opts.verbose) { fableLib.stdoutLog("\nWORKING DIR: " + opts.workingDir) + "\n"; fableLib.stdoutLog("PROJECT FILE" + (opts.projFile.length > 1 ? "S" : "") + ": " + opts.projFile.join("; ")); fableLib.stdoutLog("OUTPUT DIR: " + opts.outDir); fableLib.stdoutLog("\nFABLE COMMAND: " + fableCmd + " " + fableCmdArgs.join(" ") + "\n"); } var fableProc = child_process.spawn(fableCmd, fableCmdArgs, { cwd: opts.workingDir, windowsVerbatimArguments: true }); // Check if dotnet runtime is installed // !!child_process.spawnSync("which", ["dotnet"]).stdout.toString() // child_process.spawnSync("dotnet", ["--info"]).error != null fableProc.on('exit', function (code) { // There may be pending messages, do nothing here }); fableProc.stderr.on('data', function (data) { fableLib.stderrLog(data.toString().substring(0, 300) + "..."); fableLib.finish(1, continuation); }); var buffer = "", jsFiles = {}; fableProc.stdout.on("data", function (data) { var txt = data.toString(), newLine = 0; while (newLine >= 0) { var newLine = txt.indexOf("\n"); if (newLine == -1) { buffer += txt; } else { var json = buffer + txt.substring(0, newLine); txt = txt.substring(newLine + 1); buffer = ""; var buildFinished = /^\s*\[SIG(SUCCESS|FAIL)\]\s*$/.exec(json); if (buildFinished) { var buildSuccess = buildFinished[1] === "SUCCESS"; if (opts.rollup && buildSuccess) { bundle_1.bundle(jsFiles, opts, fableProc, continuation); } else if (opts.inMemory) { if (buildSuccess) continuation.resolve(jsFiles); else continuation.reject("Build failed"); } else { var buildResult = buildSuccess ? "SUCCESS" : "FAIL"; postbuild(opts, buildResult, fableProc, continuation); } } else { var res = processJson(json, opts, continuation); if (Array.isArray(res)) res.forEach(function (file) { return jsFiles[file.fileName] = file; }); } } } }); } function main(opts, continuation) { fableLib.stdoutLog(constants.PKG_NAME + " " + constants.PKG_VERSION + ": Start compilation..."); try { opts = options_1.readOptions(opts); if (opts.scripts && opts.scripts.prebuild) { var continuation2 = function (exitCode) { if (exitCode === 0) { build(opts, continuation); } else { fableLib.finish(exitCode, continuation); } }; fableLib.runCommand(opts.workingDir, opts.scripts.prebuild) .then(continuation2, continuation2); } else { build(opts, continuation); } } catch (err) { fableLib.stderrLog(err); fableLib.finish(1, continuation); } } /** * Starts compilation, if opts is not empty assumes it's * running from API and returns a Promise. */ function compile(opts) { if (opts) { return new Promise(function (resolve, reject) { main(opts, { resolve: resolve, reject: reject }); }); } main(opts); } exports.compile = compile;