UNPKG

3.17 kBPlain TextView Raw
1#!/usr/bin/env node
2
3import { spawn } from "child_process";
4import * as path from "path";
5import * as readline from "readline";
6
7const BIN_PATH = path.join(__dirname, "../bin/fable-cli/Fable.Cli.dll");
8
9function log(args: {[x: string]: any} | undefined, msg: string) {
10 if (!(args && args.silent)) {
11 console.log(msg);
12 }
13}
14
15// From https://gist.github.com/LeverOne/1308368
16/* tslint:disable:no-bitwise */
17function uuid() {
18 let b = "";
19 for (let a = 0; a++ < 36;) {
20 b += a * 51 & 52
21 ? (a ^ 15 ? 8 ^ Math.random() * (a ^ 20 ? 16 : 4) : 4).toString(16)
22 : "-";
23 }
24 return b;
25}
26/* tslint:enable:no-bitwise */
27
28function getVersion(): string {
29 try {
30 return require("../package.json").version;
31 } catch {
32 return "";
33 }
34}
35
36function processArgs(args?: {[x: string]: any}) {
37 let cliArgs = [BIN_PATH, "start-stdin"];
38 if (args != null) {
39 if (args.path) {
40 const filePath = path.resolve(args.path);
41 log(args, `dotnet binary: ${filePath}`);
42 cliArgs = filePath.endsWith(".dll")
43 ? [filePath, "start-stdin", "--force-pkgs"]
44 : ["run", "-c", "Release", "-p", filePath, "start-stdin", "--force-pkgs"];
45 delete args.path;
46 }
47 for (const k of Object.keys(args)) {
48 if (args[k] !== false) {
49 cliArgs.push("--" + k.replace(/[A-Z]/g, (x) => "-" + x.toLowerCase()));
50 if (args[k] !== true) {
51 cliArgs.push(args[k]);
52 }
53 }
54 }
55 }
56 return cliArgs;
57}
58
59export interface ICompilerProxy {
60 send(data: {}): Promise<{}>;
61 close(): void;
62}
63
64export default function start(cliArgs?: {}): ICompilerProxy {
65 log(cliArgs, `fable-compiler ${getVersion()}`);
66 const child = spawn("dotnet", processArgs(cliArgs));
67
68 // Error handling
69 child.on("error", (err) => {
70 console.error("Cannot spawn dotnet", err.message);
71 });
72 child.stderr.on("data", (data) => {
73 console.error(`child proccess errored: ${data}`);
74 });
75 // child.on("close", (code) => {
76 // log(cliArgs, `child process exited with code ${code}`);
77 // });
78
79 // Pending promises
80 const pending: Map<string, ((x: object) => void)> = new Map();
81
82 const linereader = readline.createInterface({
83 input: child.stdout,
84 });
85 linereader.on("line", (data: string) => {
86 const pattern = /^JSON:([\w-]+):/.exec(data);
87 if (pattern != null) {
88 const id = pattern[1];
89 const resolve = pending.get(id);
90 if (resolve != null) {
91 pending.delete(id);
92 resolve(JSON.parse(data.substr(pattern[0].length)));
93 }
94 } else { // LOG
95 log(cliArgs, data);
96 }
97 });
98
99 return {
100 send(data: {}) {
101 return new Promise((resolve) => {
102 const id = uuid();
103 pending.set(id, resolve);
104 child.stdin.write(`${id}:${JSON.stringify(data)}\n`);
105 });
106 },
107 close() {
108 child.stdin.write("exit\n");
109 },
110 };
111}
112
\No newline at end of file