@j-o-r/sh 1.1.17 → 1.1.19

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.
Files changed (3) hide show
  1. package/lib/SH.js +52 -3
  2. package/package.json +2 -2
  3. package/types/SH.d.ts +22 -5
package/lib/SH.js CHANGED
@@ -27,6 +27,7 @@
27
27
  // Modified by: jorrit.duin+sh[AT]gmail.com
28
28
  /** @type {assert} */
29
29
  import assert from 'node:assert';
30
+ import readline from 'node:readline/promises';
30
31
  import SHDispatch from './SHDispatch.js';
31
32
  import Test from './Test.js'
32
33
  import AsyncTracker from './AsyncTracker.js'
@@ -90,8 +91,13 @@ const parseDuration = (d) => {
90
91
  }
91
92
  throw new Error(`Unknown duration: "${d}".`);
92
93
  }
93
-
94
- /** @type {Shell & { (pieces: TemplateStringsArray, ...args: *): SHDispatch }} */
94
+ /**
95
+ * A template-tag that returns an SHDispatch.
96
+ * @typedef {(pieces: TemplateStringsArray, ...args: unknown[]) => SHDispatch} SHTag
97
+ */
98
+ /**
99
+ * @type {Shell & SHTag}
100
+ */
95
101
  const SH = new Proxy(function(pieces, ...args) {
96
102
  if (pieces.some((p) => p == undefined)) {
97
103
  throw new Error(`Malformed command ${pieces}`);
@@ -140,10 +146,12 @@ const within = async (callback) => {
140
146
 
141
147
  /**
142
148
  * This function reads the standard input (stdin) from the current process.
149
+ * @returns {Promise<string>}
143
150
  * @example
144
- * const content = await stdin();
151
+ * const content = await readIn();
145
152
  */
146
153
  const readIn = async () => {
154
+ if (process.stdin.isTTY) return ''; // nothing was piped
147
155
  let buf = '';
148
156
  process.stdin.setEncoding('utf8');
149
157
  for await (const chunk of process.stdin) {
@@ -152,6 +160,46 @@ const readIn = async () => {
152
160
  return buf;
153
161
  }
154
162
 
163
+
164
+ /**
165
+ * Get user input from the command line (stdin)
166
+ * @param {string} prompt - prompt or question
167
+ * @returns {Promise<string>}
168
+ * @example
169
+ * const content = await userIn();
170
+ */
171
+
172
+ const userIn = (prompt) => new Promise((resolve) => {
173
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
174
+ let buffer = '';
175
+ let timer;
176
+ /**
177
+ * @param {string} chunk
178
+ */
179
+ const onData = (chunk) => {
180
+ if (chunk.length > 4 && chunk.includes('\n')) {
181
+ clearTimeout(timer);
182
+ timer = setTimeout(resolveFunc, 50);
183
+ }
184
+ };
185
+ const resolveFunc = () => {
186
+ let fullText = buffer;
187
+ if (rl.line) fullText += rl.line;
188
+ process.stdin.removeListener('data', onData);
189
+ resolve(fullText);
190
+ rl.close();
191
+ };
192
+ rl.on('line', (line) => {
193
+ buffer += line + '\n';
194
+ clearTimeout(timer);
195
+ timer = setTimeout(resolveFunc, 50);
196
+ });
197
+ process.stdin.on('data', onData);
198
+
199
+ rl.setPrompt(prompt);
200
+ rl.prompt();
201
+ });
202
+
155
203
  /**
156
204
  * Retries a given asynchronous function a specified number of times with optional delays between attempts.
157
205
  *
@@ -301,6 +349,7 @@ export {
301
349
  sleep,
302
350
  retry,
303
351
  readIn,
352
+ userIn,
304
353
  within,
305
354
  expBackoff,
306
355
  parseArgs,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@j-o-r/sh",
3
3
  "author": "Jorrit Duin <j-o-r@duin.work>",
4
4
  "type": "module",
5
- "version": "1.1.17",
5
+ "version": "1.1.19",
6
6
  "description": "Execute shell commands on Linux-based systems from javascript",
7
7
  "main": "lib/SH.js",
8
8
  "types": "types/SH.d.ts",
@@ -13,7 +13,7 @@
13
13
  "test": "npm run test:sh",
14
14
  "test:sh": "scenarios/sh.js",
15
15
  "publish": "npm run release && npm publish --access public",
16
- "release": "npm pack --pack-destination=release",
16
+ "release": "npm run types && npm pack --pack-destination=release",
17
17
  "types": "rm types/* && tsc -p tsc.json"
18
18
  },
19
19
  "repository": {
package/types/SH.d.ts CHANGED
@@ -7,10 +7,18 @@ export type ResolveCallback = Function;
7
7
  * Creates a new SHDispatch object that represents a command to be executed.
8
8
  */
9
9
  export type Shell = Function;
10
- /** @type {Shell & { (pieces: TemplateStringsArray, ...args: *): SHDispatch }} */
11
- export const SH: Shell & {
12
- (pieces: TemplateStringsArray, ...args: any): SHDispatch;
13
- };
10
+ /**
11
+ * A template-tag that returns an SHDispatch.
12
+ */
13
+ export type SHTag = (pieces: TemplateStringsArray, ...args: unknown[]) => SHDispatch;
14
+ /**
15
+ * A template-tag that returns an SHDispatch.
16
+ * @typedef {(pieces: TemplateStringsArray, ...args: unknown[]) => SHDispatch} SHTag
17
+ */
18
+ /**
19
+ * @type {Shell & SHTag}
20
+ */
21
+ export const SH: Shell & SHTag;
14
22
  /**
15
23
  * Change working directory
16
24
  * @param {string} dir
@@ -47,11 +55,20 @@ export function sleep(duration: string | number): Promise<any>;
47
55
  export function retry(count: number, a: string | number | typeof expBackoff | Function, b?: Function): Promise<any>;
48
56
  /**
49
57
  * This function reads the standard input (stdin) from the current process.
58
+ * @returns {Promise<string>}
50
59
  * @example
51
- * const content = await stdin();
60
+ * const content = await readIn();
52
61
  */
53
62
  export function readIn(): Promise<string>;
54
63
  /**
64
+ * Get user input from the command line (stdin)
65
+ * @param {string} prompt - prompt or question
66
+ * @returns {Promise<string>}
67
+ * @example
68
+ * const content = await userIn();
69
+ */
70
+ export function userIn(prompt: string): Promise<string>;
71
+ /**
55
72
  * Create a async/sync context in new execution callstack
56
73
  * @param {function} callback - async/sync function
57
74
  * @example