Skip to content

Commit 4dc6672

Browse files
committed
refactor(node): bind lazy node-module getters to a const once
Replace inline-chained getNode*()/getFs()/getPath() calls (getFs().existsSync(x)) with a single bound const (const fs = getFs(); fs.existsSync(x)) across src/. The lazy getters memoize, but re-invoking them at every call site reads noisily and obscures the single-read intent. The two genuine spawnSync primitives (process/spawn/child + kill-tree) get an oxlint-disable-next-line socket/prefer-async-spawn with a reason — the getter rename made the previously-hidden sync call visible to that rule.
1 parent 6c9f304 commit 4dc6672

11 files changed

Lines changed: 60 additions & 37 deletions

File tree

src/bin/exec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export async function execBin(
5757
// previously cached binary is removed mid-session.
5858
/* c8 ignore start */
5959
if (cached) {
60-
if (getFs().existsSync(cached)) {
60+
const fs = getFs()
61+
if (fs.existsSync(cached)) {
6162
resolvedPath = cached
6263
} else {
6364
binPathCache.delete(binPath)

src/constants/platform.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ let memoizedArch: Arch | undefined
2828
*/
2929
export function getArch(): Arch {
3030
if (memoizedArch === undefined) {
31-
memoizedArch = getNodeOs().arch()
31+
const os = getNodeOs()
32+
memoizedArch = os.arch()
3233
}
3334
return memoizedArch
3435
}
@@ -79,7 +80,8 @@ let memoizedOs: Platform | undefined
7980
*/
8081
export function getOs(): Platform {
8182
if (memoizedOs === undefined) {
82-
memoizedOs = getNodeOs().platform()
83+
const os = getNodeOs()
84+
memoizedOs = os.platform()
8385
}
8486
return memoizedOs
8587
}

src/crypto/hash.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ export function hash(
7575
if (native !== undefined) {
7676
return native(algorithm, data, outputEncoding) as string
7777
}
78-
return getNodeCrypto()
78+
const crypto = getNodeCrypto()
79+
return crypto
7980
.createHash(algorithm)
8081
.update(data as string | Buffer)
8182
.digest(outputEncoding)

src/dlx/binary-cache.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ export async function cleanDlxCache(
116116
* ```
117117
*/
118118
export function getBinaryCacheMetadataPath(cacheEntryPath: string): string {
119-
return getNodePath().join(cacheEntryPath, '.dlx-metadata.json')
119+
const path = getNodePath()
120+
return path.join(cacheEntryPath, '.dlx-metadata.json')
120121
}
121122

122123
/**

src/fs/access.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,22 @@ export function canAccess(path: PathLike, mode?: number | undefined): boolean {
4646
* Can the process execute `path`? (`X_OK`)
4747
*/
4848
export function canExecute(path: PathLike): boolean {
49-
return canAccess(path, getNodeFs().constants.X_OK)
49+
const fs = getNodeFs()
50+
return canAccess(path, fs.constants.X_OK)
5051
}
5152

5253
/**
5354
* Can the process read `path`? (`R_OK`)
5455
*/
5556
export function canRead(path: PathLike): boolean {
56-
return canAccess(path, getNodeFs().constants.R_OK)
57+
const fs = getNodeFs()
58+
return canAccess(path, fs.constants.R_OK)
5759
}
5860

5961
/**
6062
* Can the process write `path`? (`W_OK`)
6163
*/
6264
export function canWrite(path: PathLike): boolean {
63-
return canAccess(path, getNodeFs().constants.W_OK)
65+
const fs = getNodeFs()
66+
return canAccess(path, fs.constants.W_OK)
6467
}

src/globs/match.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ export async function glob(
8787
// option surface lines up. Avoids loading fast-glob entirely.
8888
/* c8 ignore start */
8989
if (canUseNodeFsGlob(options)) {
90+
const fsPromises = getFsPromises()
9091
const out = await fromAsync(
91-
getFsPromises().glob(patterns as string | readonly string[], {
92+
fsPromises.glob(patterns as string | readonly string[], {
9293
...(options?.cwd ? { cwd: options.cwd } : {}),
9394
...(normalizedIgnore ? { exclude: normalizedIgnore } : {}),
9495
}),
@@ -126,8 +127,9 @@ export function globSync(
126127
// surface lines up. Avoids loading fast-glob entirely.
127128
/* c8 ignore start */
128129
if (canUseNodeFsGlob(options)) {
130+
const fs = getFs()
129131
return normalizeGlobResults([
130-
...getFs().globSync(patterns as string | readonly string[], {
132+
...fs.globSync(patterns as string | readonly string[], {
131133
...(options?.cwd ? { cwd: options.cwd } : {}),
132134
...(normalizedIgnore ? { exclude: normalizedIgnore } : {}),
133135
}),

src/packages/edit-class.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,10 @@ export function getEditablePackageJsonClass(): EditablePackageJsonConstructor {
285285
} = this.content as Record<string | symbol, unknown>
286286
const content = sort ? packageSort(rest) : rest
287287

288+
const util = getNodeUtil()
288289
if (
289290
ignoreWhitespace &&
290-
getNodeUtil().isDeepStrictEqual(content, this._readFileJson)
291+
util.isDeepStrictEqual(content, this._readFileJson)
291292
) {
292293
return false
293294
}
@@ -340,9 +341,10 @@ export function getEditablePackageJsonClass(): EditablePackageJsonConstructor {
340341
} = this.content as Record<string | symbol, unknown>
341342
const content = sort ? packageSort(rest) : rest
342343

344+
const util = getNodeUtil()
343345
if (
344346
ignoreWhitespace &&
345-
getNodeUtil().isDeepStrictEqual(content, this._readFileJson)
347+
util.isDeepStrictEqual(content, this._readFileJson)
346348
) {
347349
return false
348350
}

src/paths/socket.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ import { getNodePath } from '../node/path'
3838
*/
3939
export function getOsHomeDir(): string {
4040
// Always check for overrides - don't cache when using rewire
41-
return getPathValue('homedir', () => getNodeOs().homedir())
41+
const os = getNodeOs()
42+
return getPathValue('homedir', () => os.homedir())
4243
}
4344
/**
4445
* Get the OS temporary directory. Can be overridden in tests using
@@ -51,7 +52,8 @@ export function getOsHomeDir(): string {
5152
*/
5253
export function getOsTmpDir(): string {
5354
// Always check for overrides - don't cache when using rewire
54-
return getPathValue('tmpdir', () => getNodeOs().tmpdir())
55+
const os = getNodeOs()
56+
return getPathValue('tmpdir', () => os.tmpdir())
5557
}
5658
/**
5759
* Get a Socket app cache directory (~/.socket/_<appName>/cache).
@@ -61,7 +63,8 @@ export function getOsTmpDir(): string {
6163
* Get a Socket app cache directory (~/.socket/_<appName>/cache).
6264
*/
6365
export function getSocketAppCacheDir(appName: string): string {
64-
return normalizePath(getNodePath().join(getSocketAppDir(appName), CACHE_DIR))
66+
const path = getNodePath()
67+
return normalizePath(path.join(getSocketAppDir(appName), CACHE_DIR))
6568
}
6669
/**
6770
* Get a Socket app TTL cache directory (~/.socket/_<appName>/cache/ttl).
@@ -71,9 +74,8 @@ export function getSocketAppCacheDir(appName: string): string {
7174
* Get a Socket app TTL cache directory (~/.socket/_<appName>/cache/ttl).
7275
*/
7376
export function getSocketAppCacheTtlDir(appName: string): string {
74-
return normalizePath(
75-
getNodePath().join(getSocketAppCacheDir(appName), CACHE_TTL_DIR),
76-
)
77+
const path = getNodePath()
78+
return normalizePath(path.join(getSocketAppCacheDir(appName), CACHE_TTL_DIR))
7779
}
7880
/**
7981
* Get a Socket app directory (~/.socket/_<appName>).
@@ -83,8 +85,9 @@ export function getSocketAppCacheTtlDir(appName: string): string {
8385
* Get a Socket app directory (~/.socket/_<appName>).
8486
*/
8587
export function getSocketAppDir(appName: string): string {
88+
const path = getNodePath()
8689
return normalizePath(
87-
getNodePath().join(getSocketUserDir(), `${SOCKET_APP_PREFIX}${appName}`),
90+
path.join(getSocketUserDir(), `${SOCKET_APP_PREFIX}${appName}`),
8891
)
8992
}
9093
/**
@@ -115,8 +118,9 @@ export function getSocketCacacheDir(): string {
115118
if (getSocketCacacheDirEnv()) {
116119
return normalizePath(getSocketCacacheDirEnv() as string)
117120
}
121+
const path = getNodePath()
118122
return normalizePath(
119-
getNodePath().join(getSocketUserDir(), `${SOCKET_APP_PREFIX}cacache`),
123+
path.join(getSocketUserDir(), `${SOCKET_APP_PREFIX}cacache`),
120124
)
121125
})
122126
}
@@ -162,8 +166,9 @@ export function getSocketDlxDir(): string {
162166
if (getSocketDlxDirEnv()) {
163167
return normalizePath(getSocketDlxDirEnv() as string)
164168
}
169+
const path = getNodePath()
165170
return normalizePath(
166-
getNodePath().join(
171+
path.join(
167172
getSocketUserDir(),
168173
`${SOCKET_APP_PREFIX}${SOCKET_DLX_APP_NAME}`,
169174
),
@@ -202,8 +207,9 @@ export function getSocketRegistryDir(): string {
202207
* (~/.socket/_registry/cache/ttl/github).
203208
*/
204209
export function getSocketRegistryGithubCacheDir(): string {
210+
const path = getNodePath()
205211
return normalizePath(
206-
getNodePath().join(
212+
path.join(
207213
getSocketAppCacheTtlDir(SOCKET_REGISTRY_APP_NAME),
208214
CACHE_GITHUB_DIR,
209215
),
@@ -243,7 +249,8 @@ export function getSocketUserDir(): string {
243249
if (socketHome) {
244250
return normalizePath(socketHome)
245251
}
246-
return normalizePath(getNodePath().join(getUserHomeDir(), DOT_SOCKET_DIR))
252+
const path = getNodePath()
253+
return normalizePath(path.join(getUserHomeDir(), DOT_SOCKET_DIR))
247254
})
248255
}
249256
/**
@@ -272,8 +279,9 @@ export function getSocketUserDir(): string {
272279
*/
273280
export function getSocketWheelhouseDir(): string {
274281
return getPathValue('socket-wheelhouse-dir', () => {
282+
const path = getNodePath()
275283
return normalizePath(
276-
getNodePath().join(
284+
path.join(
277285
getSocketUserDir(),
278286
`${SOCKET_APP_PREFIX}${SOCKET_WHEELHOUSE_APP_NAME}`,
279287
),

src/process/lock-manager.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,9 @@ export class ProcessLockManager {
174174
try {
175175
// Use single statSync call instead of existsSync + statSync.
176176
// throwIfNoEntry: false returns undefined if path doesn't exist.
177+
const fs = getFs()
177178
// oxlint-disable-next-line socket/prefer-exists-sync -- need mtimeMs for staleness check; existsSync would discard the metadata.
178-
const stats = getFs().statSync(lockPath, { throwIfNoEntry: false })
179+
const stats = fs.statSync(lockPath, { throwIfNoEntry: false })
179180
if (!stats) {
180181
return false
181182
}
@@ -255,7 +256,8 @@ export class ProcessLockManager {
255256
// handled correctly — the previous Math.max(lastIndexOf('/'), '\\')
256257
// approach failed on relative paths and mixed-separator inputs.
257258
const fs = getFs()
258-
const parent = getPath().dirname(lockPath)
259+
const path = getPath()
260+
const parent = path.dirname(lockPath)
259261
if (parent && parent !== '.' && parent !== lockPath) {
260262
fs.mkdirSync(parent, { recursive: true })
261263
}
@@ -372,7 +374,8 @@ export class ProcessLockManager {
372374
this.stopTouchTimer(lockPath)
373375

374376
try {
375-
if (getFs().existsSync(lockPath)) {
377+
const fs = getFs()
378+
if (fs.existsSync(lockPath)) {
376379
safeDeleteSync(lockPath, { recursive: true })
377380
}
378381
this.activeLocks.delete(lockPath)

src/process/spawn/child.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,9 @@ export function spawn(
211211
// executes the exact file. Stripping would fail for files in directories
212212
// not in PATH (e.g., temp directories, project-local bins).
213213
if (!isPath(actualCmd)) {
214+
const path = getNodePath()
214215
// Extract just the command name without extension for PATH lookup.
215-
actualCmd = getNodePath().basename(
216-
actualCmd,
217-
getNodePath().extname(actualCmd),
218-
)
216+
actualCmd = path.basename(actualCmd, path.extname(actualCmd))
219217
}
220218
}
221219
/* c8 ignore stop */
@@ -459,11 +457,9 @@ export function spawnSync(
459457
// executes the exact file. Stripping would fail for files in directories
460458
// not in PATH (e.g., temp directories, project-local bins).
461459
if (!isPath(actualCmd)) {
460+
const path = getNodePath()
462461
// Extract just the command name without extension for PATH lookup.
463-
actualCmd = getNodePath().basename(
464-
actualCmd,
465-
getNodePath().extname(actualCmd),
466-
)
462+
actualCmd = path.basename(actualCmd, path.extname(actualCmd))
467463
}
468464
}
469465
/* c8 ignore stop */
@@ -478,7 +474,9 @@ export function spawnSync(
478474
...rawSpawnOptions,
479475
} as NodeSpawnOptions & { encoding: BufferEncoding | 'buffer' }
480476
const stdioString = spawnOptions.encoding !== 'buffer'
481-
const result = getNodeChildProcess().spawnSync(actualCmd, args, spawnOptions)
477+
const childProcess = getNodeChildProcess()
478+
// oxlint-disable-next-line socket/prefer-async-spawn -- this IS the lib's sync spawn primitive; it must call the underlying spawnSync.
479+
const result = childProcess.spawnSync(actualCmd, args, spawnOptions)
482480
if (stdioString) {
483481
const { stderr, stdout } = result
484482
if (stdout) {

0 commit comments

Comments
 (0)