Skip to content

Commit 5e486bc

Browse files
committed
feat: add process utilities for safe command execution
1 parent 981911e commit 5e486bc

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

README.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ GoodbyeNJN's utility library for TypeScript and JavaScript, providing a collecti
1212
- 📦 **Modular**: Import only what you need with tree-shakable exports
1313
- 🛡️ **Result Type**: Functional error handling with Result pattern
1414
- 📁 **File System**: Safe file system operations with Result types
15-
- 🧰 **Common Utils**: String, math, promise, and other utility functions
15+
- 🧰 **Common Utils**: String, math, promise, process, and other utility functions
1616
- 📊 **Remeda Extensions**: Extended utilities built on top of Remeda
1717

1818
## Installation
@@ -30,7 +30,7 @@ yarn add @goodbyenjn/utils
3030
### Common Utilities
3131

3232
```typescript
33-
import { sleep, template, unindent, debounce } from "@goodbyenjn/utils";
33+
import { sleep, template, unindent, debounce, $ } from "@goodbyenjn/utils";
3434

3535
// Promise utilities
3636
await sleep(1000); // Sleep for 1 second
@@ -45,6 +45,15 @@ const code = unindent`
4545
}
4646
`;
4747

48+
// Process utilities - Execute shell commands safely
49+
const result = await $`ls -la`;
50+
if (result.isOk()) {
51+
console.log("stdout:", result.value.stdout);
52+
console.log("stderr:", result.value.stderr);
53+
} else {
54+
console.error("Command failed:", result.error);
55+
}
56+
4857
// Throttling and debouncing
4958
const debouncedFn = debounce(() => console.log("Called!"), 300);
5059
```
@@ -134,7 +143,7 @@ type NumberType = YieldType<typeof numberGenerator>; // number
134143

135144
### Available Modules
136145

137-
- **Main (`@goodbyenjn/utils`)** - Common utilities (string, math, promise, error handling, etc.)
146+
- **Main (`@goodbyenjn/utils`)** - Common utilities (string, math, promise, process, error handling, etc.)
138147
- **File System (`@goodbyenjn/utils/fs`)** - Safe file system operations
139148
- **Result (`@goodbyenjn/utils/result`)** - Functional error handling
140149
- **Remeda (`@goodbyenjn/utils/remeda`)** - Extended Remeda utilities
@@ -157,6 +166,10 @@ type NumberType = YieldType<typeof numberGenerator>; // number
157166
- `createSingleton(factory)` - Create singleton factory
158167
- `PromiseWithResolvers` - Promise with external resolvers
159168

169+
#### Process Utilities
170+
171+
- `$(command)` - Execute shell commands safely, returns ResultAsync with stdout/stderr
172+
160173
#### Math Utilities
161174

162175
- `linear(value, range)` - Linear interpolation

src/common/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ export { linear, scale } from "./math";
44

55
export { parseKeyValuePairs, parseValueToBoolean } from "./parse";
66

7+
export { $ } from "./process";
8+
79
export { PromiseWithResolvers, createLock, createSingleton, sleep } from "./promise";
810

911
export {

src/common/process.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { isString } from "@/remeda";
2+
import { ResultAsync } from "@/result";
3+
4+
import { errorToMessage } from "./error";
5+
import { PromiseWithResolvers } from "./promise";
6+
7+
export const $ = (cmd: TemplateStringsArray | string) => {
8+
const command = isString(cmd) ? cmd : cmd[0]!;
9+
10+
const promise = import("node:child_process").then(({ exec }) => {
11+
const { promise, reject, resolve } = PromiseWithResolvers<{
12+
stdout: string;
13+
stderr: string;
14+
}>();
15+
16+
exec(command, (error, stdout, stderr) => {
17+
if (error) {
18+
reject(error);
19+
} else {
20+
resolve({ stdout, stderr });
21+
}
22+
});
23+
24+
return promise;
25+
});
26+
27+
return ResultAsync.fromPromise(promise, errorToMessage(`Failed to execute command: ${cmd}`));
28+
};

0 commit comments

Comments
 (0)