From 10f69940324e1a413544b1018ae0aebcf9f32247 Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Sat, 2 Jan 2021 16:27:11 +0100 Subject: [PATCH] Initial commit --- .gitignore | 3 ++ package-lock.json | 24 ++++++++++++++ package.json | 21 +++++++++++++ src/index.ts | 80 +++++++++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 19 +++++++++++ 5 files changed, 147 insertions(+) create mode 100644 .gitignore create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/index.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1af6435 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/@types/ +/lib/ +/node_modules/ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8ccb89a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,24 @@ +{ + "name": "simple-spawn", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/node": { + "version": "14.14.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.19.tgz", + "integrity": "sha512-4nhBPStMK04rruRVtVc6cDqhu7S9GZai0fpXgPXrFpcPX6Xul8xnrjSdGB4KPBVYG/R5+fXWdCM8qBoiULWGPQ==" + }, + "emittery": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.0.tgz", + "integrity": "sha512-XMGToId3CejfmZg/0qOzdTT3WFuAN8fQYtcKXccabRfCzGiWMSTydMshHGLyx9C/ejMl4nw9tvqrn12QVFPIUg==" + }, + "typescript": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6600270 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "simple-spawn", + "version": "0.1.0", + "description": "Simple process spawning utility for node.js", + "main": "dist/index.js", + "types": "./@types/index.d.ts", + "scripts": { + "build": "tsc", + "watch": "npm run build -- --watch" + }, + "repository": "https://git.kuba-orlik.name/kuba/node-simple-spawn", + "author": "Kuba Orlik", + "license": "ISC", + "dependencies": { + "@types/node": "^14.14.19", + "emittery": "^0.8.0" + }, + "devDependencies": { + "typescript": "^4.1.3" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..1c2dac7 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,80 @@ +import { ChildProcessWithoutNullStreams, spawn } from "child_process"; +import Emittery from "emittery"; + +export default function simpleSpawn( + cmd: string, + arg: string[] +): Promise { + const process = spawn(cmd, arg); + let output = ""; + let err = ""; + return new Promise((resolve, reject) => { + process.on("close", (code) => { + code === 0 ? resolve(output) : reject(err); + }); + process.stdout.on("data", (data) => (output += data.toString("utf-8"))); + process.stderr.on("data", (data) => (err += data.toString("utf-8"))); + }); +} + +class DeferedSpawn extends Emittery { + constructor(private process: ChildProcessWithoutNullStreams) { + super(); + } + + async waitForAnswer() { + return new Promise((resolve, reject) => { + this.on("success", resolve); + this.on("error", reject); + }); + } + + async waitForNextData(): Promise { + return new Promise((resolve, reject) => { + this.on("data", (data) => resolve(data.toString("utf-8"))); + this.on("error", reject); + this.on("end", () => resolve(null)); + }); + } + + kill() { + process.kill(-this.process.pid); // https://stackoverflow.com/a/49842576 + debugger; + console.log("killed map!"); + } +} + +export function deferedSpawn( + cmd: string, + arg: string[] +): Promise { + const process = spawn(cmd, arg, { detached: true }); + let spawned = false; + let output = ""; + let err = ""; + const emitter = new DeferedSpawn(process); + return new Promise((resolve, reject) => { + process.stdout.on("data", (data) => { + output += data.toString("utf-8"); + emitter.emit("data", data); + }); + process.stderr.on("data", (data) => { + err += data.toString("utf-8"); + }); + process.on("spawn", () => { + resolve(emitter); + }); + process.on("close", (code) => { + if (!spawned) { + reject(err); + } else { + if (code === 0) { + emitter.emit("success", output); + } else { + emitter.emit("error", err); + } + emitter.emit("end", { err, output }); + } + }); + }); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ce33b64 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "node", + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "target": "ES2020", + "declaration": true, + "esModuleInterop": true, + "lib": ["es6", "esnext"], + "outDir": "lib", + "checkJs": true, + "allowJs": true, + "declarationDir": "@types", + "sourceMap": true + }, + "include": ["src/**/*"] +}