Commit a32e54c

Anton Golub <antongolub@antongolub.com>
2025-06-18 21:47:38
refactor: simplify `retry` impl
1 parent 8643029
build/cli.cjs
@@ -34,11 +34,11 @@ var import_deps = require("./deps.cjs");
 // src/repl.ts
 var import_node_os = __toESM(require("os"), 1);
 var import_node_path = __toESM(require("path"), 1);
+var import_node_process = __toESM(require("process"), 1);
 var import_node_repl = __toESM(require("repl"), 1);
 var import_node_util = require("util");
 var import_core = require("./core.cjs");
 var import_vendor_core = require("./vendor-core.cjs");
-var import_node_process = __toESM(require("process"), 1);
 var _a;
 var HISTORY = (_a = import_node_process.default.env.ZX_REPL_HISTORY) != null ? _a : import_node_path.default.join(import_node_os.default.homedir(), ".zx_repl_history");
 function startRepl() {
build/cli.js
build/core.cjs
@@ -287,8 +287,7 @@ var log = function(entry) {
   const stream = log.output || import_node_process.default.stderr;
   const format = ((_a = log.formatters) == null ? void 0 : _a[entry.kind]) || formatters[entry.kind];
   if (!format) return;
-  const data = format(entry);
-  stream.write(data);
+  stream.write(format(entry));
 };
 var SPACE_RE = /\s/;
 var SYNTAX = "()[]{}<>;:+|&=";
build/index.cjs
@@ -174,33 +174,23 @@ function stdin() {
     return buf;
   });
 }
-function retry(count, a, b) {
+function retry(count, d, cb) {
   return __async(this, null, function* () {
+    if (typeof d === "function") return retry(count, 0, d);
+    (0, import_node_assert.default)(cb);
     const total = count;
-    let callback;
-    let delayStatic = 0;
-    let delayGen;
-    if (typeof a === "function") {
-      callback = a;
-    } else {
-      if (typeof a === "object") {
-        delayGen = a;
-      } else {
-        delayStatic = (0, import_util.parseDuration)(a);
-      }
-      (0, import_node_assert.default)(b);
-      callback = b;
-    }
-    let lastErr;
+    const getDelay = typeof d === "object" ? d : function* () {
+      while (true) yield (0, import_util.parseDuration)(d);
+    }();
     let attempt = 0;
+    let lastErr;
     while (count-- > 0) {
       attempt++;
       try {
-        return yield callback();
+        return yield cb();
       } catch (err) {
-        let delay = 0;
-        if (delayStatic > 0) delay = delayStatic;
-        if (delayGen) delay = delayGen.next().value;
+        lastErr = err;
+        const delay = getDelay.next().value;
         import_core.$.log({
           kind: "retry",
           total,
@@ -211,9 +201,7 @@ function retry(count, a, b) {
           error: `FAIL Attempt: ${attempt}/${total}, next: ${delay}`
           // legacy
         });
-        lastErr = err;
-        if (count == 0) break;
-        if (delay) yield sleep(delay);
+        if (delay > 0) yield sleep(delay);
       }
     }
     throw lastErr;
src/goods.ts
@@ -174,34 +174,31 @@ export async function retry<T>(
 ): Promise<T>
 export async function retry<T>(
   count: number,
-  a: Duration | Generator<number> | (() => T),
-  b?: () => T
+  d: Duration | Generator<number> | (() => T),
+  cb?: () => T
 ): Promise<T> {
+  if (typeof d === 'function') return retry(count, 0, d)
+
+  assert(cb)
+
   const total = count
-  let callback: () => T
-  let delayStatic = 0
-  let delayGen: Generator<number> | undefined
-  if (typeof a === 'function') {
-    callback = a
-  } else {
-    if (typeof a === 'object') {
-      delayGen = a
-    } else {
-      delayStatic = parseDuration(a)
-    }
-    assert(b)
-    callback = b
-  }
-  let lastErr: unknown
+  const getDelay =
+    typeof d === 'object'
+      ? d
+      : (function* () {
+          while (true) yield parseDuration(d)
+        })()
+
   let attempt = 0
+  let lastErr: unknown
   while (count-- > 0) {
     attempt++
     try {
-      return await callback()
+      return await cb()
     } catch (err) {
-      let delay = 0
-      if (delayStatic > 0) delay = delayStatic
-      if (delayGen) delay = delayGen.next().value
+      lastErr = err
+      const delay = getDelay.next().value
+
       $.log({
         kind: 'retry',
         total,
@@ -211,9 +208,7 @@ export async function retry<T>(
         verbose: !$.quiet && $.verbose,
         error: `FAIL Attempt: ${attempt}/${total}, next: ${delay}`, // legacy
       })
-      lastErr = err
-      if (count == 0) break
-      if (delay) await sleep(delay)
+      if (delay > 0) await sleep(delay)
     }
   }
   throw lastErr
src/log.ts
@@ -116,8 +116,8 @@ export const log: Log = function (entry) {
     entry: LogEntry
   ) => string | Buffer
   if (!format) return // ignore unknown log entries
-  const data = format(entry)
-  stream.write(data)
+
+  stream.write(format(entry))
 }
 
 const SPACE_RE = /\s/
src/repl.ts
@@ -14,11 +14,11 @@
 
 import os from 'node:os'
 import path from 'node:path'
+import process from 'node:process'
 import repl from 'node:repl'
 import { inspect } from 'node:util'
 import { ProcessOutput, defaults } from './core.ts'
 import { chalk } from './vendor-core.ts'
-import process from 'node:process'
 
 const HISTORY =
   process.env.ZX_REPL_HISTORY ?? path.join(os.homedir(), '.zx_repl_history')
test/error.test.ts
@@ -96,9 +96,11 @@ describe('error', () => {
     })
   })
 
+  // prettier-ignore
   test('getExitMessage()', () => {
     assert.match(formatExitMessage(2, null, '', ''), /Misuse of shell builtins/)
-    assert.match(formatExitMessage(1, 'SIGKILL', '', ''), /SIGKILL/)
+    assert.equal(formatExitMessage(1, 'SIGKILL', '', '', 'data'), `\n    at \n    exit code: 1\n    signal: SIGKILL\n    details: \ndata`)
+    assert.equal(formatExitMessage(0, null, '', ''), 'exit code: 0')
   })
 
   test('getErrorMessage()', () => {
test/goods.test.ts
@@ -125,12 +125,25 @@ describe('goods', () => {
     })
 
     test('works with custom delay and limit', async () => {
+      const now = Date.now()
+      let count = 0
       try {
         await retry(3, '2ms', () => {
+          count++
           throw new Error('fail')
         })
       } catch (e) {
         assert.match(e.message, /fail/)
+        assert.ok(Date.now() >= now + 4)
+        assert.equal(count, 3)
+      }
+    })
+
+    test('trows undefined on count misconfiguration', async () => {
+      try {
+        await retry(0, () => 'ok')
+      } catch (e) {
+        assert.equal(e, undefined)
       }
     })
 
.size-limit.json
@@ -29,7 +29,7 @@
       "build/globals.js",
       "build/deno.js"
     ],
-    "limit": "812.15 kB",
+    "limit": "811.90 kB",
     "brotli": false,
     "gzip": false
   },
@@ -62,7 +62,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "867.65 kB",
+    "limit": "867.40 kB",
     "brotli": false,
     "gzip": false
   }