node_child_process/
lib.rs

1use js_sys::{Array, Object};
2use node_sys::*;
3use wasm_bindgen::prelude::*;
4
5#[wasm_bindgen(module = "node:child_process")]
6extern "C" {
7
8    pub fn spawn(cmd: &str) -> ChildProcess;
9
10    #[wasm_bindgen(js_name = spawn)]
11    pub fn spawn_with_args(cmd: &str, args: &SpawnArgs) -> ChildProcess;
12
13    #[wasm_bindgen(js_name = spawn)]
14    pub fn spawn_with_args_and_options(
15        cmd: &str,
16        args: &SpawnArgs,
17        options: &SpawnOptions,
18    ) -> ChildProcess;
19
20    #[wasm_bindgen(extends = Array)]
21    #[derive(Debug, Clone, PartialEq, Eq)]
22    pub type SpawnArgs;
23
24    #[wasm_bindgen(extends = Object)]
25    #[derive(Debug, Clone, PartialEq, Eq)]
26    pub type SpawnOptions;
27
28    #[wasm_bindgen(extends = EventEmitter)]
29    #[derive(Clone, Debug)]
30    pub type ChildProcess;
31
32    #[wasm_bindgen(method, getter)]
33    pub fn exit_code(this: &ChildProcess) -> u64;
34
35    #[wasm_bindgen(method, getter)]
36    pub fn pid(this: &ChildProcess) -> u64;
37
38    #[wasm_bindgen(method, getter)]
39    pub fn stdout(this: &ChildProcess) -> ReadableStream;
40
41    #[wasm_bindgen(method, getter)]
42    pub fn stderr(this: &ChildProcess) -> ReadableStream;
43
44    #[wasm_bindgen(method, getter)]
45    pub fn stdin(this: &ChildProcess) -> WritableStream;
46
47    #[wasm_bindgen(method)]
48    pub fn kill(this: &ChildProcess) -> bool;
49
50    #[wasm_bindgen(method, js_name=kill)]
51    fn kill_with_signal_impl(this: &ChildProcess, signal: JsValue) -> bool;
52}
53
54unsafe impl Send for ChildProcess {}
55unsafe impl Sync for ChildProcess {}
56
57pub enum KillSignal<'s> {
58    None,
59    SIGKILL,
60    SIGTERM,
61    Message(&'s str),
62    Code(u32),
63}
64
65impl ChildProcess {
66    pub fn kill_with_signal(self: &ChildProcess, signal: KillSignal) -> bool {
67        match signal {
68            KillSignal::None => self.kill(),
69            KillSignal::SIGKILL => self.kill_with_signal_impl(JsValue::from("SIGKILL")),
70            KillSignal::SIGTERM => self.kill_with_signal_impl(JsValue::from("SIGTERM")),
71            KillSignal::Message(str) => self.kill_with_signal_impl(JsValue::from(str)),
72            KillSignal::Code(code) => self.kill_with_signal_impl(JsValue::from(code)),
73        }
74    }
75}
76
77impl From<Vec<&str>> for SpawnArgs {
78    fn from(list: Vec<&str>) -> Self {
79        let array = Array::new();
80        for (index, value) in list.iter().enumerate() {
81            array.set(index as u32, JsValue::from(*value));
82        }
83
84        #[allow(unused_mut)]
85        let mut args: Self = ::wasm_bindgen::JsCast::unchecked_into(array);
86        args
87    }
88}
89
90impl From<&[&str]> for SpawnArgs {
91    fn from(list: &[&str]) -> Self {
92        let array = Array::new();
93        for (index, value) in list.iter().enumerate() {
94            array.set(index as u32, JsValue::from(*value));
95        }
96
97        #[allow(unused_mut)]
98        let mut args: Self = ::wasm_bindgen::JsCast::unchecked_into(array);
99        args
100    }
101}
102
103impl From<&[String]> for SpawnArgs {
104    fn from(list: &[String]) -> Self {
105        let array = Array::new();
106        for (index, value) in list.iter().enumerate() {
107            array.set(index as u32, JsValue::from(value));
108        }
109
110        #[allow(unused_mut)]
111        let mut args: Self = ::wasm_bindgen::JsCast::unchecked_into(array);
112        args
113    }
114}
115
116impl Default for SpawnOptions {
117    fn default() -> Self {
118        Self::new()
119    }
120}
121
122impl SpawnOptions {
123    /// "Construct a new `SpawnOptions`.
124    ///
125    /// [NODEJS Documentation](https://nodejs.org/api/child_process.html#child_processspawncommand-args-options)
126    pub fn new() -> Self {
127        #[allow(unused_mut)]
128        let mut ret: Self = ::wasm_bindgen::JsCast::unchecked_into(Object::new());
129        ret
130    }
131
132    pub fn set(&self, key: &str, value: JsValue) -> &Self {
133        let r = ::js_sys::Reflect::set(self.as_ref(), &JsValue::from(key), &value);
134        debug_assert!(
135            r.is_ok(),
136            "setting properties should never fail on our dictionary objects"
137        );
138        let _ = r;
139        self
140    }
141
142    pub fn cwd(&self, cwd: &str) -> &Self {
143        self.set("cwd", JsValue::from(cwd))
144    }
145
146    pub fn env(&self, env: ProcessEnv) -> &Self {
147        self.set("env", JsValue::from(env))
148    }
149
150    pub fn argv0(&self, argv0: &str) -> &Self {
151        self.set("argv0", JsValue::from(argv0))
152    }
153
154    pub fn detached(&self, detached: bool) -> &Self {
155        self.set("detached", JsValue::from(detached))
156    }
157
158    pub fn uid(&self, uid: &str) -> &Self {
159        self.set("uid", JsValue::from(uid))
160    }
161
162    pub fn gid(&self, gid: &str) -> &Self {
163        self.set("gid", JsValue::from(gid))
164    }
165
166    pub fn serialization(&self, serialization: &str) -> &Self {
167        self.set("serialization", JsValue::from(serialization))
168    }
169
170    pub fn shell(&self, shell: bool) -> &Self {
171        self.set("shell", JsValue::from(shell))
172    }
173
174    pub fn shell_str(&self, shell: &str) -> &Self {
175        self.set("shell", JsValue::from(shell))
176    }
177
178    pub fn windows_verbatim_arguments(&self, args: bool) -> &Self {
179        self.set("windowsVerbatimArguments", JsValue::from(args))
180    }
181
182    pub fn windows_hide(&self, windows_hide: bool) -> &Self {
183        self.set("windowsHide", JsValue::from(windows_hide))
184    }
185
186    pub fn timeout(&self, timeout: u32) -> &Self {
187        self.set("timeout", JsValue::from(timeout))
188    }
189
190    // TODO: AbortSignal
191
192    pub fn kill_signal(&self, signal: u32) -> &Self {
193        self.set("killSignal", JsValue::from(signal))
194    }
195
196    pub fn kill_signal_str(&self, signal: &str) -> &Self {
197        self.set("killSignal", JsValue::from(signal))
198    }
199}