Skip to content

Commit 6d43650

Browse files
committed
fix: surface scan findings across dlx + stdio + promise-queue
- src/promise-queue.ts: wrap task.fn() via Promise.resolve().then() so a sync throw inside the task function converts into a proper rejection routed to task.reject instead of escaping as an uncaught exception. - src/stdio/progress.ts: clamp negative ms in formatTime() so a negative ETA (current > total due to over-ticking or clock skew) no longer renders as "-1m59s". - src/dlx/lockfile.ts: wrap the scratch-dir safeDelete in finally with its own try/catch so a cleanup failure doesn't clobber the real exception from the try-block. - src/dlx/package.ts: normalize parsePackageSpec to return `version: undefined` for a bare trailing "@" (e.g. "pkg@") so downstream "no version" checks behave consistently. - src/dlx/manifest.ts: correct the @fileoverview "Primary API" list to match the actual DlxManifest methods (get/set/clear/clearAll/isFresh/ getManifestEntry) and flag setPackageEntry/setBinaryEntry as deprecated. From scan findings: not fixing stdio/prompts.ts's silent swallow — the tests in test/unit/stdio/prompts.test.mts explicitly assert that non-TypeError rejections return undefined (that's the documented Ctrl-C path). Discarded three scanner claims that were wrong (already handled by existing guards). Full suite: 6290 passing.
1 parent 424cfd7 commit 6d43650

5 files changed

Lines changed: 27 additions & 9 deletions

File tree

src/dlx/lockfile.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ export async function generatePackagePin(
228228
lockfile: ideal.lockfile,
229229
}
230230
} finally {
231-
await safeDelete(scratch, { force: true })
231+
// Swallow cleanup failures so a scratch-dir-delete error doesn't
232+
// mask the real exception from the try-block.
233+
try {
234+
await safeDelete(scratch, { force: true })
235+
} catch {}
232236
}
233237
}

src/dlx/manifest.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33
* Manages persistent caching of DLX package and binary metadata with TTL support
44
* and atomic file operations.
55
*
6-
* Key Functions:
7-
* - getManifestEntry: Retrieve manifest entry by spec
8-
* - setPackageEntry: Store npm package metadata
9-
* - setBinaryEntry: Store binary download metadata
6+
* Primary API (on {@link DlxManifest}):
7+
* - `getManifestEntry(spec)` — retrieve a manifest entry by spec
8+
* - `set(name, record)` — store a raw `StoreRecord`
9+
* - `get(name)` — read a raw `StoreRecord`
10+
* - `clear(name)` / `clearAll()` — eviction
11+
* - `isFresh(record, ttlMs)` — TTL check
12+
*
13+
* Legacy typed setters `setPackageEntry` and `setBinaryEntry` exist but
14+
* are deprecated; new callers should construct a `StoreRecord` and use
15+
* `set(name, record)` directly.
1016
*
1117
* Features:
1218
* - TTL-based cache expiration

src/dlx/package.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,9 +851,12 @@ export function parsePackageSpec(spec: string): {
851851
// No version or scoped package without version (@ only at position 0).
852852
return { name: spec, version: undefined }
853853
}
854+
const sliced = spec.slice(atIndex + 1)
854855
return {
855856
name: spec.slice(0, atIndex),
856-
version: spec.slice(atIndex + 1),
857+
// A trailing `@` (e.g. `'pkg@'`) yields an empty slice — normalize
858+
// to undefined so downstream "no version" checks behave.
859+
version: sliced || undefined,
857860
}
858861
}
859862
}

src/promise-queue.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,11 @@ export class PromiseQueue {
7070

7171
this.running++
7272

73-
task
74-
.fn()
73+
// Wrap in Promise.resolve().then() so a synchronous throw inside
74+
// task.fn() converts into a rejection routed to task.reject rather
75+
// than escaping as an uncaught exception.
76+
Promise.resolve()
77+
.then(() => task.fn())
7578
.then(task.resolve)
7679
.catch(task.reject)
7780
.finally(() => {

src/stdio/progress.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,9 @@ export class ProgressBar {
232232
* Format time in seconds to human readable.
233233
*/
234234
private formatTime(ms: number): string {
235-
const seconds = Math.round(ms / 1000)
235+
// Clamp negatives (can happen when current > total due to over-ticking
236+
// or clock skew) to 0 so we don't render "-1m59s".
237+
const seconds = Math.max(0, Math.round(ms / 1000))
236238
if (seconds < 60) {
237239
return `${seconds}s`
238240
}

0 commit comments

Comments
 (0)