Skip to content

Commit 5546c6d

Browse files
committed
refactor(paths,fs): push memoization to individual path getters
Move memoization from safeDelete's getAllowedDirectories() helper down to the individual path getter functions. This provides better separation of concerns and benefits all callers, not just safeDelete. Changes: - Add memoization to getSocketUserDir() in src/paths.ts - Add memoization to getSocketCacacheDir() in src/paths.ts - Add new getOsTmpDir() helper with memoization in src/paths.ts - Update safeDelete/safeDeleteSync to use memoized getters directly - Remove getAllowedDirectories() helper and _cachedAllowedDirs variable - Remove unused getOs() helper and _os variable Benefits: - Memoization is now reusable across entire codebase - Each getter is responsible for its own performance optimization - Cleaner, more maintainable code structure - No change in behavior, just better architecture
1 parent e947e8b commit 5546c6d

File tree

2 files changed

+81
-81
lines changed

2 files changed

+81
-81
lines changed

src/fs.ts

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -329,24 +329,6 @@ function getPath() {
329329
return _path as typeof import('path')
330330
}
331331

332-
let _os: typeof import('os') | undefined
333-
/**
334-
* Lazily load the os module to avoid Webpack errors.
335-
* Uses non-'node:' prefixed require to prevent Webpack bundling issues.
336-
*
337-
* @returns The Node.js os module
338-
* @private
339-
*/
340-
/*@__NO_SIDE_EFFECTS__*/
341-
function getOs() {
342-
if (_os === undefined) {
343-
// Use non-'node:' prefixed require to avoid Webpack errors.
344-
345-
_os = /*@__PURE__*/ require('node:os')
346-
}
347-
return _os as typeof import('os')
348-
}
349-
350332
/**
351333
* Process directory entries and filter for directories.
352334
* Filters entries to include only directories, optionally excluding empty ones.
@@ -1074,38 +1056,6 @@ export function readJsonSync(
10741056
})
10751057
}
10761058

1077-
// Lazy cache for allowed directories to avoid re-resolving on every safeDelete call
1078-
let _cachedAllowedDirs: string[] | undefined
1079-
1080-
/**
1081-
* Get allowed directories for safe deletion with lazy caching.
1082-
* These directories don't change during process lifetime, so we cache them.
1083-
*/
1084-
function getAllowedDirectories(): string[] {
1085-
if (_cachedAllowedDirs === undefined) {
1086-
const os = getOs()
1087-
const path = getPath()
1088-
const {
1089-
getSocketCacacheDir,
1090-
getSocketUserDir,
1091-
} = /*@__PURE__*/ require('#lib/paths')
1092-
1093-
const tmpDir = os.tmpdir()
1094-
const resolvedTmpDir = path.resolve(tmpDir)
1095-
const cacacheDir = getSocketCacacheDir()
1096-
const resolvedCacacheDir = path.resolve(cacacheDir)
1097-
const socketUserDir = getSocketUserDir()
1098-
const resolvedSocketUserDir = path.resolve(socketUserDir)
1099-
1100-
_cachedAllowedDirs = [
1101-
resolvedTmpDir,
1102-
resolvedCacacheDir,
1103-
resolvedSocketUserDir,
1104-
]
1105-
}
1106-
return _cachedAllowedDirs
1107-
}
1108-
11091059
/**
11101060
* Safely delete a file or directory asynchronously with built-in protections.
11111061
* Uses `del` for safer deletion that prevents removing cwd and above by default.
@@ -1146,7 +1096,18 @@ export async function safeDelete(
11461096
let shouldForce = opts.force !== false
11471097
if (!shouldForce && patterns.length > 0) {
11481098
const path = getPath()
1149-
const allowedDirs = getAllowedDirectories()
1099+
const {
1100+
getOsTmpDir,
1101+
getSocketCacacheDir,
1102+
getSocketUserDir,
1103+
} = /*@__PURE__*/ require('#lib/paths')
1104+
1105+
// Get allowed directories (all are memoized for performance)
1106+
const allowedDirs = [
1107+
path.resolve(getOsTmpDir()),
1108+
path.resolve(getSocketCacacheDir()),
1109+
path.resolve(getSocketUserDir()),
1110+
]
11501111

11511112
// Check if all patterns are within allowed directories.
11521113
const allInAllowedDirs = patterns.every(pattern => {
@@ -1221,7 +1182,18 @@ export function safeDeleteSync(
12211182
let shouldForce = opts.force !== false
12221183
if (!shouldForce && patterns.length > 0) {
12231184
const path = getPath()
1224-
const allowedDirs = getAllowedDirectories()
1185+
const {
1186+
getOsTmpDir,
1187+
getSocketCacacheDir,
1188+
getSocketUserDir,
1189+
} = /*@__PURE__*/ require('#lib/paths')
1190+
1191+
// Get allowed directories (all are memoized for performance)
1192+
const allowedDirs = [
1193+
path.resolve(getOsTmpDir()),
1194+
path.resolve(getSocketCacacheDir()),
1195+
path.resolve(getSocketUserDir()),
1196+
]
12251197

12261198
// Check if all patterns are within allowed directories.
12271199
const allInAllowedDirs = patterns.every(pattern => {

src/paths.ts

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,17 @@ import { getUserprofile } from '#env/windows'
2525

2626
import { normalizePath } from './path'
2727

28+
let _cachedOsTmpDir: string | undefined
29+
2830
/**
29-
* Get the user's home directory.
30-
* Uses environment variables directly to support test mocking.
31-
* Falls back to os.homedir() if env vars not set.
31+
* Get the OS temporary directory.
32+
* Result is memoized for performance.
3233
*/
33-
function _getUserHomeDir(): string {
34-
// Try HOME first (Unix)
35-
const home = getHome()
36-
if (home) {
37-
return home
38-
}
39-
// Try USERPROFILE (Windows)
40-
const userProfile = getUserprofile()
41-
if (userProfile) {
42-
return userProfile
34+
export function getOsTmpDir(): string {
35+
if (_cachedOsTmpDir === undefined) {
36+
_cachedOsTmpDir = os.tmpdir()
4337
}
44-
// Fallback to os.homedir()
45-
return os.homedir()
38+
return _cachedOsTmpDir
4639
}
4740

4841
/**
@@ -53,16 +46,22 @@ export function getSocketHomePath(): string {
5346
return getSocketUserDir()
5447
}
5548

49+
let _cachedSocketUserDir: string | undefined
50+
5651
/**
5752
* Get the Socket user directory (~/.socket).
53+
* Result is memoized for performance.
5854
*/
5955
export function getSocketUserDir(): string {
60-
return normalizePath(
61-
path.join(
62-
_getUserHomeDir(),
63-
/*@__INLINE__*/ require('#constants/paths').DOT_SOCKET_DIR,
64-
),
65-
)
56+
if (_cachedSocketUserDir === undefined) {
57+
_cachedSocketUserDir = normalizePath(
58+
path.join(
59+
getUserHomeDir(),
60+
/*@__INLINE__*/ require('#constants/paths').DOT_SOCKET_DIR,
61+
),
62+
)
63+
}
64+
return _cachedSocketUserDir
6665
}
6766

6867
/**
@@ -77,20 +76,29 @@ export function getSocketAppDir(appName: string): string {
7776
)
7877
}
7978

79+
let _cachedSocketCacacheDir: string | undefined
80+
8081
/**
8182
* Get the Socket cacache directory (~/.socket/_cacache).
8283
* Can be overridden with SOCKET_CACACHE_DIR environment variable for testing.
84+
* Result is memoized for performance.
8385
*/
8486
export function getSocketCacacheDir(): string {
85-
if (getSocketCacacheDirEnv()) {
86-
return normalizePath(getSocketCacacheDirEnv() as string)
87+
if (_cachedSocketCacacheDir === undefined) {
88+
if (getSocketCacacheDirEnv()) {
89+
_cachedSocketCacacheDir = normalizePath(
90+
getSocketCacacheDirEnv() as string,
91+
)
92+
} else {
93+
_cachedSocketCacacheDir = normalizePath(
94+
path.join(
95+
getSocketUserDir(),
96+
`${/*@__INLINE__*/ require('#constants/socket').SOCKET_APP_PREFIX}cacache`,
97+
),
98+
)
99+
}
87100
}
88-
return normalizePath(
89-
path.join(
90-
getSocketUserDir(),
91-
`${/*@__INLINE__*/ require('#constants/socket').SOCKET_APP_PREFIX}cacache`,
92-
),
93-
)
101+
return _cachedSocketCacacheDir
94102
}
95103

96104
/**
@@ -164,3 +172,23 @@ export function getSocketRegistryGithubCacheDir(): string {
164172
),
165173
)
166174
}
175+
176+
/**
177+
* Get the user's home directory.
178+
* Uses environment variables directly to support test mocking.
179+
* Falls back to os.homedir() if env vars not set.
180+
*/
181+
export function getUserHomeDir(): string {
182+
// Try HOME first (Unix)
183+
const home = getHome()
184+
if (home) {
185+
return home
186+
}
187+
// Try USERPROFILE (Windows)
188+
const userProfile = getUserprofile()
189+
if (userProfile) {
190+
return userProfile
191+
}
192+
// Fallback to os.homedir()
193+
return os.homedir()
194+
}

0 commit comments

Comments
 (0)