UNPKG

8.55 kBJavaScriptView Raw
1"use strict";
2var path = require("path");
3var child_process = require("child_process");
4var fableLib = require("./lib");
5var constants = require("./constants");
6var bundle_1 = require("./bundle");
7var watch_1 = require("./watch");
8var options_1 = require("./options");
9/** Processes a JSON received from .NET process. If it's a Babel AST it will be compiled. */
10function processJson(json, opts, continuation) {
11 try {
12 var babelAst = void 0;
13 try {
14 babelAst = JSON.parse(json);
15 }
16 catch (_err) {
17 return null; // If stdout is not in JSON format, just ignore
18 }
19 if (babelAst.type == "LOG") {
20 if (babelAst.message.indexOf("[WARNING]") == 0) {
21 fableLib.stdoutLog(babelAst.message.replace("[WARNING]", "").trim());
22 }
23 else if (opts.verbose) {
24 fableLib.stdoutLog(babelAst.message);
25 }
26 }
27 else if (babelAst.type == "ERROR") {
28 throw babelAst;
29 }
30 else if (opts.rollup) {
31 return fableLib.babelify(babelAst, opts);
32 }
33 else {
34 fableLib.babelifyToFile(babelAst, opts);
35 }
36 }
37 catch (err) {
38 fableLib.stderrLog(err);
39 if (!opts.watch) {
40 fableLib.finish(1, continuation);
41 }
42 }
43 return null;
44}
45/** Runs the postbuild script and starts watching if necessary */
46function postbuild(opts, buildResult, fableProc, continuation) {
47 var parallelProc = null;
48 // The "postbuild-once" script must be run only once (well done, Captain Obvious)
49 // and it musn't wait till the process is finished, as it's normally used
50 // to fire up watch mode of bundlers (Webpack, Rollup...)
51 if (buildResult === "SUCCESS" && opts.scripts && opts.scripts["postbuild-once"]) {
52 var postbuildScript = opts.scripts["postbuild-once"];
53 delete opts.scripts["postbuild-once"];
54 parallelProc = fableLib.runCommandInParallel(opts.workingDir, postbuildScript);
55 }
56 // If present, run "postbuild" script after every build and wait till it's finished
57 // to exit the process or start watch mode
58 if (buildResult === "SUCCESS" && opts.scripts && opts.scripts.postbuild) {
59 var continuation2 = function (exitCode) {
60 if (!opts.watch) {
61 fableLib.finish(exitCode, continuation);
62 }
63 else {
64 watch_1.watch(opts, buildResult, fableProc, parallelProc, continuation);
65 }
66 };
67 fableLib.runCommand(opts.workingDir, opts.scripts.postbuild)
68 .then(continuation2, continuation2);
69 }
70 else if (!opts.watch) {
71 fableLib.finish(buildResult === "SUCCESS" ? 0 : 1, continuation);
72 }
73 else {
74 watch_1.watch(opts, buildResult, fableProc, parallelProc, continuation);
75 }
76}
77exports.postbuild = postbuild;
78/** Builds the project, requires child_process */
79function build(opts, continuation) {
80 function wrapInQuotes(arg) {
81 if (process.platform === "win32") {
82 arg = arg.toString().trim();
83 return arg.indexOf(" ") > 0 && arg[0] != '"' ? '"' + arg + '"' : arg;
84 }
85 else {
86 return arg;
87 }
88 }
89 ;
90 var fableBin = path.resolve(__dirname, "bin/Fable.Client.Node.exe");
91 if (constants.PKG_NAME === "fable-compiler-netcore") {
92 fableBin = fableBin.replace(".exe", ".dll");
93 }
94 var fableCmd, fableCmdArgs = [wrapInQuotes(fableBin)];
95 if (constants.PKG_NAME === "fable-compiler-netcore") {
96 fableCmd = "dotnet";
97 }
98 else {
99 fableCmd = process.platform === "win32" ? null : "mono";
100 }
101 for (var k in opts) {
102 if (constants.FABLE_BIN_OPTIONS.has(k)) {
103 if (k === "watch" || k === "rollup")
104 fableCmdArgs.push("--" + k, String(!!opts[k])); // Cast to boolean
105 else if (Array.isArray(opts[k]))
106 opts[k].forEach(function (v) { return fableCmdArgs.push("--" + k, wrapInQuotes(v)); });
107 else if (typeof opts[k] === "object")
108 Object.getOwnPropertyNames(opts[k]).forEach(function (k2) {
109 return fableCmdArgs.push("--" + k, wrapInQuotes(k2 + "=" + opts[k][k2]));
110 });
111 else
112 fableCmdArgs.push("--" + k, wrapInQuotes(opts[k]));
113 }
114 }
115 if (process.platform === "win32") {
116 if (fableCmd) {
117 fableCmdArgs.splice(0, 0, fableCmd);
118 }
119 fableCmd = "cmd";
120 fableCmdArgs = ["/S", "/C", '"' + fableCmdArgs.join(" ") + '"'];
121 }
122 // Call Fable.exe
123 if (opts.verbose) {
124 fableLib.stdoutLog("\nWORKING DIR: " + opts.workingDir) + "\n";
125 fableLib.stdoutLog("PROJECT FILE" + (opts.projFile.length > 1 ? "S" : "") + ": " + opts.projFile.join("; "));
126 fableLib.stdoutLog("OUTPUT DIR: " + opts.outDir);
127 fableLib.stdoutLog("\nFABLE COMMAND: " + fableCmd + " " + fableCmdArgs.join(" ") + "\n");
128 }
129 var fableProc = child_process.spawn(fableCmd, fableCmdArgs, {
130 cwd: opts.workingDir,
131 windowsVerbatimArguments: true
132 });
133 // Check if dotnet runtime is installed
134 // !!child_process.spawnSync("which", ["dotnet"]).stdout.toString()
135 // child_process.spawnSync("dotnet", ["--info"]).error != null
136 fableProc.on('exit', function (code) {
137 // There may be pending messages, do nothing here
138 });
139 fableProc.stderr.on('data', function (data) {
140 fableLib.stderrLog(data.toString().substring(0, 300) + "...");
141 fableLib.finish(1, continuation);
142 });
143 var buffer = "", jsFiles = {};
144 fableProc.stdout.on("data", function (data) {
145 var txt = data.toString(), newLine = 0;
146 while (newLine >= 0) {
147 var newLine = txt.indexOf("\n");
148 if (newLine == -1) {
149 buffer += txt;
150 }
151 else {
152 var json = buffer + txt.substring(0, newLine);
153 txt = txt.substring(newLine + 1);
154 buffer = "";
155 var buildFinished = /^\s*\[SIG(SUCCESS|FAIL)\]\s*$/.exec(json);
156 if (buildFinished) {
157 var buildSuccess = buildFinished[1] === "SUCCESS";
158 if (opts.rollup && buildSuccess) {
159 bundle_1.bundle(jsFiles, opts, fableProc, continuation);
160 }
161 else if (opts.inMemory) {
162 if (buildSuccess)
163 continuation.resolve(jsFiles);
164 else
165 continuation.reject("Build failed");
166 }
167 else {
168 var buildResult = buildSuccess ? "SUCCESS" : "FAIL";
169 postbuild(opts, buildResult, fableProc, continuation);
170 }
171 }
172 else {
173 var res = processJson(json, opts, continuation);
174 if (Array.isArray(res))
175 res.forEach(function (file) { return jsFiles[file.fileName] = file; });
176 }
177 }
178 }
179 });
180}
181function main(opts, continuation) {
182 fableLib.stdoutLog(constants.PKG_NAME + " " + constants.PKG_VERSION + ": Start compilation...");
183 try {
184 opts = options_1.readOptions(opts);
185 if (opts.scripts && opts.scripts.prebuild) {
186 var continuation2 = function (exitCode) {
187 if (exitCode === 0) {
188 build(opts, continuation);
189 }
190 else {
191 fableLib.finish(exitCode, continuation);
192 }
193 };
194 fableLib.runCommand(opts.workingDir, opts.scripts.prebuild)
195 .then(continuation2, continuation2);
196 }
197 else {
198 build(opts, continuation);
199 }
200 }
201 catch (err) {
202 fableLib.stderrLog(err);
203 fableLib.finish(1, continuation);
204 }
205}
206/**
207 * Starts compilation, if opts is not empty assumes it's
208 * running from API and returns a Promise.
209*/
210function compile(opts) {
211 if (opts) {
212 return new Promise(function (resolve, reject) {
213 main(opts, { resolve: resolve, reject: reject });
214 });
215 }
216 main(opts);
217}
218exports.compile = compile;