simple-stdout 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,15 +2,38 @@
2
2
 
3
3
  Run a shell command and get the `stdout` as a string.
4
4
 
5
- ## Usage
5
+ ```javascript
6
+ const name = await stdout('git config --get user.name')
7
+ ```
8
+
9
+ That's it. Just a tiny library with no frills.
10
+
11
+ ## Install
6
12
 
7
13
  ```sh
8
- pnpm install simple-stdout
14
+ pnpm add simple-stdout
15
+
16
+ # or
17
+ yarn add simple-stdout
18
+
19
+ # or
20
+ npm install simple-stdout
9
21
  ```
10
22
 
23
+ ## Usage
24
+
11
25
  ```javascript
12
26
  import stdout from 'simple-stdout'
13
27
 
14
- console.log(await stdout('echo "Hello, world!"'))
15
- // Logs 'Hello, world!'
28
+ const name = await stdout('git config --get user.name')
29
+ // 'Gérald Genta'
30
+ ```
31
+
32
+ Need `execFile` instead? (Safer for untrusted input, no shell injection worries.)
33
+
34
+ ```javascript
35
+ import { stdoutFile } from 'simple-stdout'
36
+
37
+ const name = await stdoutFile('git', ['config', '--get', 'user.name'])
38
+ // 'Gérald Genta'
16
39
  ```
package/dist/index.d.ts CHANGED
@@ -1,4 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import type { ExecFileOptions, ExecOptions } from 'node:child_process';
1
3
  /**
2
4
  * Returns stdout from the given shell command
5
+ *
6
+ * Calls `child_process.exec` under the hood.
3
7
  */
4
- export default function stdout(command: string): Promise<string>;
8
+ export default function stdout(command: string, options?: ExecOptions): Promise<string>;
9
+ /**
10
+ * Returns stdout from executing the given file/executable
11
+ *
12
+ * Calls `child_process.execFile` under the hood.
13
+ */
14
+ export declare function stdoutFile(file: string, args?: readonly string[], options?: ExecFileOptions): Promise<string>;
package/dist/index.js CHANGED
@@ -1,17 +1,42 @@
1
- import { exec } from 'node:child_process';
1
+ #!/usr/bin/env node
2
+ import { exec, execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ const asyncExec = promisify(exec);
5
+ /**
6
+ * Removes trailing newline
7
+ */
8
+ const cleanOutput = (output) => output.replace(/\n$/, '');
2
9
  /**
3
10
  * Returns stdout from the given shell command
11
+ *
12
+ * Calls `child_process.exec` under the hood.
13
+ */
14
+ export default async function stdout(command, options) {
15
+ const { stdout, stderr } = await asyncExec(command, options);
16
+ if (stderr) {
17
+ throw new Error(stderr.toString());
18
+ }
19
+ if (typeof stdout !== 'string') {
20
+ return cleanOutput(stdout.toString());
21
+ }
22
+ // Remove trailing newline
23
+ return cleanOutput(stdout);
24
+ }
25
+ const asyncExecFile = promisify(execFile);
26
+ /**
27
+ * Returns stdout from executing the given file/executable
28
+ *
29
+ * Calls `child_process.execFile` under the hood.
4
30
  */
5
- export default async function stdout(command) {
6
- return new Promise((resolve, reject) => {
7
- exec(command, (err, stdout, stderr) => {
8
- if (err || stderr) {
9
- reject(err || new Error(stderr));
10
- }
11
- else if (typeof stdout === 'string') {
12
- resolve(stdout.replace(/\n$/, '')); // Remove trailing newline
13
- }
14
- });
15
- });
31
+ export async function stdoutFile(file, args, options) {
32
+ const { stdout, stderr } = await asyncExecFile(file, args, options);
33
+ if (stderr) {
34
+ throw new Error(stderr.toString());
35
+ }
36
+ if (typeof stdout !== 'string') {
37
+ return cleanOutput(stdout.toString());
38
+ }
39
+ // Remove trailing newline
40
+ return cleanOutput(stdout);
16
41
  }
17
42
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAEzC;;GAEG;AACH,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,MAAM,CAAC,OAAe;IAChD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YAClC,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;gBAChB,MAAM,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;YACpC,CAAC;iBAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACpC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAA,CAAC,0BAA0B;YACjE,CAAC;QACL,CAAC,CAAC,CAAA;IACN,CAAC,CAAC,CAAA;AACN,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;AAEjC;;GAEG;AACH,MAAM,WAAW,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAEzE;;;;GAIG;AACH,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,MAAM,CAAC,OAAe,EAAE,OAAqB;IACvE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAE5D,IAAI,MAAM,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;IACzC,CAAC;IAED,0BAA0B;IAC1B,OAAO,WAAW,CAAC,MAAM,CAAC,CAAA;AAC9B,CAAC;AAED,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAEzC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,IAAwB,EAAE,OAAyB;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IAEnE,IAAI,MAAM,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;IACzC,CAAC;IAED,0BAA0B;IAC1B,OAAO,WAAW,CAAC,MAAM,CAAC,CAAA;AAC9B,CAAC"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "simple-stdout",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "scripts": {
5
- "build": "tsc",
5
+ "build": "tsc -p tsconfig.build.json",
6
6
  "test": "vitest .",
7
7
  "test:once": "vitest run",
8
8
  "format": "prettier --write --list-different .",
@@ -15,6 +15,9 @@
15
15
  },
16
16
  "type": "module",
17
17
  "main": "./dist/index.js",
18
+ "bin": {
19
+ "simple-stdout": "./dist/index.js"
20
+ },
18
21
  "files": [
19
22
  "dist"
20
23
  ],
@@ -28,10 +31,10 @@
28
31
  "husky": "^9.1.7",
29
32
  "prettier": "3.7.4",
30
33
  "typescript": "^5.8.3",
31
- "typescript-eslint": "^8.50.1",
34
+ "typescript-eslint": "^8.52.0",
32
35
  "vitest": "^4.0.16"
33
36
  },
34
- "packageManager": "pnpm@10.26.2",
37
+ "packageManager": "pnpm@10.27.0",
35
38
  "engines": {
36
39
  "node": ">=20"
37
40
  },
@@ -1 +0,0 @@
1
- export {};
@@ -1,73 +0,0 @@
1
- import { existsSync, unlinkSync } from 'node:fs';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
4
- import { describe, expect, it } from 'vitest';
5
- import stdout from './index.js';
6
- describe('stdout()', () => {
7
- it('should run a command and return its stdout', async () => {
8
- const result = await stdout('echo "Hello, world!"');
9
- expect(result).toBe('Hello, world!');
10
- });
11
- it('should remove trailing newline', async () => {
12
- const result = await stdout('echo "No trailing newline"');
13
- expect(result).toBe('No trailing newline');
14
- });
15
- it('should reject on error', async () => {
16
- await expect(stdout('nonexistent-command')).rejects.toThrow();
17
- });
18
- it('should reject on empty command', async () => {
19
- await expect(stdout('')).rejects.toThrow();
20
- });
21
- it('should reject on stderr output', async () => {
22
- await expect(stdout('echo "This will cause an error" >&2')).rejects.toThrow();
23
- });
24
- it('should handle commands with arguments', async () => {
25
- const result = await stdout('echo "Argument test"');
26
- expect(result).toBe('Argument test');
27
- });
28
- it('should handle commands with multiple lines', async () => {
29
- const result = await stdout('echo "Line 1\nLine 2"');
30
- expect(result).toBe('Line 1\nLine 2');
31
- });
32
- it('should handle commands with special characters', async () => {
33
- const result = await stdout('echo "Special characters: !@#$%^&*()"');
34
- expect(result).toBe('Special characters: !@#$%^&*()');
35
- });
36
- it('should handle commands with spaces', async () => {
37
- const result = await stdout('echo "Command with spaces"');
38
- expect(result).toBe('Command with spaces');
39
- });
40
- it('should handle commands with quotes', async () => {
41
- const result = await stdout('echo "Quoted text"');
42
- expect(result).toBe('Quoted text');
43
- });
44
- it('should handle commands with multiple arguments', async () => {
45
- const result = await stdout('echo "Multiple" "Arguments"');
46
- expect(result).toBe('Multiple Arguments');
47
- });
48
- it('should handle commands with environment variables', async () => {
49
- const result = await stdout('echo $HOME');
50
- expect(result).toBe(process.env.HOME || '');
51
- });
52
- it('should handle commands with pipes', async () => {
53
- const result = await stdout('echo "Piped output" | sed "s/Piped/Modified/"');
54
- expect(result).toBe('Modified output');
55
- });
56
- it('should handle commands with redirection', async () => {
57
- const tempFile = join(tmpdir(), `stdout-test-${process.pid}.txt`);
58
- const result = await stdout(`echo "Redirected output" > ${tempFile} && cat ${tempFile}`);
59
- expect(result).toBe('Redirected output');
60
- // Clean up
61
- if (existsSync(tempFile))
62
- unlinkSync(tempFile);
63
- });
64
- it('should handle commands with subshells', async () => {
65
- const result = await stdout('echo $(echo "Subshell output")');
66
- expect(result).toBe('Subshell output');
67
- });
68
- it('should handle commands with background processes', async () => {
69
- const result = await stdout('echo "Background process" & wait');
70
- expect(result).toBe('Background process');
71
- });
72
- });
73
- //# sourceMappingURL=index.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}