@vzn/vx 0.0.173 → 0.0.175

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vzn/vx",
3
- "version": "0.0.173",
3
+ "version": "0.0.175",
4
4
  "description": "A fast, correct task runner and build cache for JavaScript monorepos.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -17,10 +17,10 @@
17
17
  "node": ">=18"
18
18
  },
19
19
  "optionalDependencies": {
20
- "@vzn/vx-linux-x64": "0.0.173",
21
- "@vzn/vx-linux-arm64": "0.0.173",
22
- "@vzn/vx-darwin-x64": "0.0.173",
23
- "@vzn/vx-darwin-arm64": "0.0.173"
20
+ "@vzn/vx-linux-x64": "0.0.175",
21
+ "@vzn/vx-linux-arm64": "0.0.175",
22
+ "@vzn/vx-darwin-x64": "0.0.175",
23
+ "@vzn/vx-darwin-arm64": "0.0.175"
24
24
  },
25
25
  "dependencies": {
26
26
  "@anthropic-ai/sandbox-runtime": "^0.0.76"
@@ -146,7 +146,7 @@ const MAX_CLOSURE_FILES = 32
146
146
  // `require` without naming it as `arguments[1]`, and one reading a file
147
147
  // outside its closure so replayed the old bytes (D-36).
148
148
  const IMPURE_RE =
149
- /\b(?:process|Bun|globalThis|global|self|fetch|Date|Temporal|Intl|crypto|performance|navigator|require|eval|Function|constructor|localeCompare|await|toLocale\w*|Reflect|getPrototypeOf|setPrototypeOf|getOwnPropertyNames|getOwnPropertyDescriptor|getOwnPropertyDescriptors|__proto__|prototype|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|random|prompt|confirm|alert|arguments)\b|import\s*\.\s*meta|\bimport\s*\(/
149
+ /\b(?:process|Bun|globalThis|global|self|fetch|Date|Temporal|Intl|crypto|performance|navigator|require|eval|Function|constructor|localeCompare|await|toLocale\w*|Reflect|getPrototypeOf|setPrototypeOf|getOwnPropertyNames|getOwnPropertyDescriptor|getOwnPropertyDescriptors|__proto__|prototype|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|random|prompt|confirm|alert|arguments|Worker)\b|import\s*\.\s*meta|\bimport\s*\(/
150
150
 
151
151
  /** Literal text that names a way to `Function` when used as a computed key. */
152
152
  const IMPURE_LITERAL_RE = /constructor|__proto__|prototype/
@@ -4,6 +4,7 @@ import path from 'node:path'
4
4
  import type { ProjectConfig, WorkspaceConfig } from '../config.js'
5
5
  import {
6
6
  BUN_GLOB_WILDCARDS,
7
+ isOutOfFds,
7
8
  relPosix,
8
9
  slashBraceExpansions,
9
10
  UserError,
@@ -84,7 +85,8 @@ export async function findWorkspaceRoot(
84
85
  let globs: string[] | null
85
86
  try {
86
87
  globs = await readPackageGlobs(dir, reads)
87
- } catch {
88
+ } catch (err) {
89
+ if (isOutOfFds(err)) throw err
88
90
  // An unparseable manifest is still a root SIGNAL (the pre-existing
89
91
  // behaviour probed only for existence); it just can't claim members.
90
92
  // `loadWorkspace` surfaces the parse error if this dir is chosen.
@@ -405,8 +407,8 @@ async function memberDirs(root: string, pattern: string): Promise<string[]> {
405
407
  let entries: import('node:fs').Dirent[]
406
408
  try {
407
409
  entries = await readdir(base, { withFileTypes: true })
408
- } catch {
409
- return []
410
+ } catch (err) {
411
+ return absent(err, [])
410
412
  }
411
413
  const dirs: string[] = []
412
414
  for (const e of entries) {
@@ -416,8 +418,8 @@ async function memberDirs(root: string, pattern: string): Promise<string[]> {
416
418
  try {
417
419
  if ((await stat(path.join(base, e.name))).isDirectory())
418
420
  dirs.push(path.join(base, e.name))
419
- } catch {
420
- // dangling link: not a member
421
+ } catch (err) {
422
+ absent(err, undefined) // dangling link: not a member
421
423
  }
422
424
  }
423
425
  }
@@ -468,8 +470,8 @@ async function findConfigFile(dir: string): Promise<string | null> {
468
470
  let entries: Dirent[]
469
471
  try {
470
472
  entries = await readdir(dir, { withFileTypes: true })
471
- } catch {
472
- return null
473
+ } catch (err) {
474
+ return absent(err, null)
473
475
  }
474
476
  // By precedence slot, not a Map per directory, and no `path.join`: at
475
477
  // 5,000 projects that cut `listProjects` from 53.5 to 47.7 ms (min of
@@ -499,11 +501,22 @@ const CONFIG_RANK = new Map(PROJECT_CONFIG_FILENAMES.map((n, i) => [n, i]))
499
501
  async function isFile(p: string): Promise<boolean> {
500
502
  try {
501
503
  return (await stat(p)).isFile()
502
- } catch {
503
- return false
504
+ } catch (err) {
505
+ return absent(err, false)
504
506
  }
505
507
  }
506
508
 
509
+ /**
510
+ * A read that found nothing is absent; one the process could not make is
511
+ * not. Out of descriptors (`EMFILE`), every member read failed, and the
512
+ * catches here read the workspace as empty: "No package matched the
513
+ * workspace's package globs" (D-60).
514
+ */
515
+ function absent<T>(err: unknown, value: T): T {
516
+ if (isOutOfFds(err)) throw err
517
+ return value
518
+ }
519
+
507
520
  export async function listProjects(workspace: Workspace): Promise<ProjectMeta[]> {
508
521
  // Run all package globs concurrently. Disk-bound walks parallelize
509
522
  // well; serializing them just stretches the discovery phase by N×.
@@ -537,7 +550,7 @@ export async function listProjects(workspace: Workspace): Promise<ProjectMeta[]>
537
550
  findConfigFile(dir),
538
551
  Bun.file(pkgJsonPath)
539
552
  .text()
540
- .catch(() => null),
553
+ .catch((err: unknown) => absent(err, null)),
541
554
  ])
542
555
  if (text === null) return null
543
556
  const pkg = parsePackageJson(text, pkgJsonPath)