@socketsecurity/lib 1.1.2 → 1.2.0
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/CHANGELOG.md +18 -0
- package/dist/agent.js +3 -0
- package/dist/agent.js.map +2 -2
- package/dist/bin.js +7 -5
- package/dist/bin.js.map +2 -2
- package/dist/dlx-binary.d.ts +1 -0
- package/dist/dlx-binary.js +1 -1
- package/dist/dlx-binary.js.map +2 -2
- package/dist/dlx-package.d.ts +35 -0
- package/dist/dlx-package.js +151 -0
- package/dist/dlx-package.js.map +7 -0
- package/dist/external/libnpmpack.js +70 -72
- package/dist/git.js +3 -2
- package/dist/git.js.map +2 -2
- package/dist/path.js +11 -3
- package/dist/path.js.map +2 -2
- package/dist/paths.js.map +2 -2
- package/dist/temporary-executor.js +2 -1
- package/dist/temporary-executor.js.map +2 -2
- package/package.json +5 -1
package/dist/git.js
CHANGED
|
@@ -44,6 +44,7 @@ __export(git_exports, {
|
|
|
44
44
|
});
|
|
45
45
|
module.exports = __toCommonJS(git_exports);
|
|
46
46
|
var import_node_path = __toESM(require("node:path"));
|
|
47
|
+
var import_platform = require("#constants/platform");
|
|
47
48
|
var import_globs = require("./globs");
|
|
48
49
|
var import_path = require("./path");
|
|
49
50
|
var import_spawn = require("./spawn");
|
|
@@ -79,7 +80,7 @@ function getGitDiffSpawnArgs(cwd) {
|
|
|
79
80
|
["status", "--porcelain"],
|
|
80
81
|
{
|
|
81
82
|
cwd: resolvedCwd,
|
|
82
|
-
shell:
|
|
83
|
+
shell: import_platform.WIN32
|
|
83
84
|
}
|
|
84
85
|
],
|
|
85
86
|
unstaged: [
|
|
@@ -94,7 +95,7 @@ function getGitDiffSpawnArgs(cwd) {
|
|
|
94
95
|
["diff", "--cached", "--name-only"],
|
|
95
96
|
{
|
|
96
97
|
cwd: resolvedCwd,
|
|
97
|
-
shell:
|
|
98
|
+
shell: import_platform.WIN32
|
|
98
99
|
}
|
|
99
100
|
]
|
|
100
101
|
};
|
package/dist/git.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/git.ts"],
|
|
4
|
-
"sourcesContent": ["import path from 'node:path'\n\nimport { getGlobMatcher } from './globs'\nimport { normalizePath } from './path'\nimport { spawn, spawnSync } from './spawn'\nimport { stripAnsi } from './strings'\n\n/**\n * Options for git diff operations.\n *\n * Controls how git diff results are processed and returned.\n *\n * @example\n * ```typescript\n * // Get absolute file paths\n * const files = await getChangedFiles({ absolute: true })\n * // => ['/path/to/repo/src/file.ts']\n *\n * // Get relative paths with caching disabled\n * const files = await getChangedFiles({ cache: false })\n * // => ['src/file.ts']\n *\n * // Get files from specific directory\n * const files = await getChangedFiles({ cwd: '/path/to/repo/src' })\n * ```\n */\nexport interface GitDiffOptions {\n /**\n * Return absolute file paths instead of relative paths.\n *\n * @default false\n */\n absolute?: boolean | undefined\n /**\n * Cache git diff results to avoid repeated git subprocess calls.\n *\n * Caching is keyed by the git command and options used, so different\n * option combinations maintain separate cache entries.\n *\n * @default true\n */\n cache?: boolean | undefined\n /**\n * Working directory for git operations.\n *\n * Git operations will be run from this directory, and returned paths\n * will be relative to the git repository root. Symlinks are resolved\n * using `fs.realpathSync()`.\n *\n * @default process.cwd()\n */\n cwd?: string | undefined\n /**\n * Parse git porcelain format output (status codes like `M`, `A`, `??`).\n *\n * When `true`, strips the two-character status code and space from the\n * beginning of each line. Automatically enabled for `getChangedFiles()`.\n *\n * @default false\n */\n porcelain?: boolean | undefined\n /**\n * Return results as a `Set` instead of an array.\n *\n * @default false\n */\n asSet?: boolean | undefined\n /**\n * Additional options passed to glob matcher.\n *\n * Supports options like `dot`, `ignore`, `nocase` for filtering results.\n */\n [key: string]: unknown\n}\n\n/**\n * Options for filtering packages by git changes.\n *\n * Used to determine which packages in a monorepo have changed files.\n *\n * @example\n * ```typescript\n * // Filter packages with changes\n * const changed = filterPackagesByChanges(packages)\n *\n * // Force include all packages\n * const all = filterPackagesByChanges(packages, { force: true })\n *\n * // Use custom package key\n * const changed = filterPackagesByChanges(\n * packages,\n * { packageKey: 'directory' }\n * )\n * ```\n */\nexport interface FilterPackagesByChangesOptions {\n /**\n * Force include all packages regardless of changes.\n *\n * @default false\n */\n force?: boolean | undefined\n /**\n * Key to access package path in package objects.\n *\n * @default 'path'\n */\n packageKey?: string | undefined\n /**\n * Additional options for filtering.\n */\n [key: string]: unknown\n}\n\ntype SpawnArgs = [string, string[], Record<string, unknown>]\n\ninterface GitDiffSpawnArgs {\n all: SpawnArgs\n unstaged: SpawnArgs\n staged: SpawnArgs\n}\n\nconst gitDiffCache = new Map<string, string[]>()\n\nlet _fs: typeof import('fs') | undefined\n/**\n * Lazily load the `fs` module to avoid Webpack errors.\n *\n * Uses non-`node:` prefixed require internally to prevent Webpack from\n * attempting to bundle Node.js built-in modules.\n *\n * @returns The Node.js `fs` module.\n *\n * @example\n * ```typescript\n * const fs = getFs()\n * const exists = fs.existsSync('/path/to/file')\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getFs() {\n if (_fs === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _fs = /*@__PURE__*/ require('node:fs')\n }\n return _fs as typeof import('fs')\n}\n\nlet _path: typeof import('path') | undefined\n/**\n * Lazily load the `path` module to avoid Webpack errors.\n *\n * Uses non-`node:` prefixed require internally to prevent Webpack from\n * attempting to bundle Node.js built-in modules.\n *\n * @returns The Node.js `path` module.\n *\n * @example\n * ```typescript\n * const path = getPath()\n * const joined = path.join('/foo', 'bar')\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getPath() {\n if (_path === undefined) {\n _path = /*@__PURE__*/ require('node:path')\n }\n return _path as typeof import('path')\n}\n\n/**\n * Get the git executable path.\n *\n * Currently always returns `'git'`, relying on the system PATH to resolve\n * the git binary location. This may be extended in the future to support\n * custom git paths.\n *\n * @returns The git executable name or path.\n *\n * @example\n * ```typescript\n * const git = getGitPath()\n * // => 'git'\n * ```\n */\nfunction getGitPath(): string {\n return 'git'\n}\n\n/**\n * Get the current working directory for git operations.\n *\n * Returns the real path to handle symlinks correctly. This is important\n * because symlinked directories like `/tmp -> /private/tmp` can cause\n * path mismatches when comparing git output.\n *\n * @returns The resolved real path of `process.cwd()`.\n *\n * @example\n * ```typescript\n * const cwd = getCwd()\n * // In /tmp (symlink to /private/tmp):\n * // => '/private/tmp'\n * ```\n */\nfunction getCwd(): string {\n return getFs().realpathSync(process.cwd())\n}\n\n/**\n * Get spawn arguments for different git diff operations.\n *\n * Prepares argument arrays for `spawn()`/`spawnSync()` calls that retrieve:\n * - `all`: All changed files (staged, unstaged, untracked) via `git status --porcelain`\n * - `unstaged`: Unstaged modifications via `git diff --name-only`\n * - `staged`: Staged changes via `git diff --cached --name-only`\n *\n * Automatically resolves symlinks in the provided `cwd` and enables shell\n * mode on Windows for proper command execution.\n *\n * @param cwd - Working directory for git operations, defaults to `process.cwd()`.\n * @returns Object containing spawn arguments for all, unstaged, and staged operations.\n */\nfunction getGitDiffSpawnArgs(cwd?: string | undefined): GitDiffSpawnArgs {\n const resolvedCwd = cwd ? getFs().realpathSync(cwd) : getCwd()\n return {\n all: [\n getGitPath(),\n ['status', '--porcelain'],\n {\n cwd: resolvedCwd,\n shell: process.platform === 'win32',\n },\n ],\n unstaged: [\n getGitPath(),\n ['diff', '--name-only'],\n {\n cwd: resolvedCwd,\n },\n ],\n staged: [\n getGitPath(),\n ['diff', '--cached', '--name-only'],\n {\n cwd: resolvedCwd,\n shell: process.platform === 'win32',\n },\n ],\n }\n}\n\n/**\n * Execute git diff command asynchronously and parse results.\n *\n * Internal helper for async git operations. Handles caching, command execution,\n * and result parsing. Returns empty array on git command failure.\n *\n * @param args - Spawn arguments tuple `[command, args, options]`.\n * @param options - Git diff options for caching and parsing.\n * @returns Promise resolving to array of file paths.\n */\nasync function innerDiff(\n args: SpawnArgs,\n options?: GitDiffOptions | undefined,\n): Promise<string[]> {\n const { cache = true, ...parseOptions } = { __proto__: null, ...options }\n const cacheKey = cache ? JSON.stringify({ args, parseOptions }) : undefined\n if (cache && cacheKey) {\n const result = gitDiffCache.get(cacheKey)\n if (result) {\n return result\n }\n }\n let result: string[]\n try {\n // Use stdioString: false to get raw Buffer, then convert ourselves to preserve exact output.\n const spawnResult = await spawn(args[0], args[1], {\n ...args[2],\n stdioString: false,\n })\n const stdout = Buffer.isBuffer(spawnResult.stdout)\n ? spawnResult.stdout.toString('utf8')\n : String(spawnResult.stdout)\n // Extract spawn cwd from args to pass to parser\n const spawnCwd =\n typeof args[2]['cwd'] === 'string' ? args[2]['cwd'] : undefined\n result = parseGitDiffStdout(stdout, parseOptions, spawnCwd)\n } catch {\n return []\n }\n if (cache && cacheKey) {\n gitDiffCache.set(cacheKey, result)\n }\n return result\n}\n\n/**\n * Execute git diff command synchronously and parse results.\n *\n * Internal helper for sync git operations. Handles caching, command execution,\n * and result parsing. Returns empty array on git command failure.\n *\n * @param args - Spawn arguments tuple `[command, args, options]`.\n * @param options - Git diff options for caching and parsing.\n * @returns Array of file paths.\n */\nfunction innerDiffSync(\n args: SpawnArgs,\n options?: GitDiffOptions | undefined,\n): string[] {\n const { cache = true, ...parseOptions } = { __proto__: null, ...options }\n const cacheKey = cache ? JSON.stringify({ args, parseOptions }) : undefined\n if (cache && cacheKey) {\n const result = gitDiffCache.get(cacheKey)\n if (result) {\n return result\n }\n }\n let result: string[]\n try {\n // Use stdioString: false to get raw Buffer, then convert ourselves to preserve exact output.\n const spawnResult = spawnSync(args[0], args[1], {\n ...args[2],\n stdioString: false,\n })\n const stdout = Buffer.isBuffer(spawnResult.stdout)\n ? spawnResult.stdout.toString('utf8')\n : String(spawnResult.stdout)\n // Extract spawn cwd from args to pass to parser\n const spawnCwd =\n typeof args[2]['cwd'] === 'string' ? args[2]['cwd'] : undefined\n result = parseGitDiffStdout(stdout, parseOptions, spawnCwd)\n } catch {\n return []\n }\n if (cache && cacheKey) {\n gitDiffCache.set(cacheKey, result)\n }\n return result\n}\n\n/**\n * Find git repository root by walking up from the given directory.\n *\n * Searches for a `.git` directory or file by traversing parent directories\n * upward until found or filesystem root is reached. Returns the original path\n * if no git repository is found.\n *\n * This function is exported primarily for testing purposes.\n *\n * @param startPath - Directory path to start searching from.\n * @returns Git repository root path, or `startPath` if not found.\n *\n * @example\n * ```typescript\n * const root = findGitRoot('/path/to/repo/src/subdir')\n * // => '/path/to/repo'\n *\n * const notFound = findGitRoot('/not/a/repo')\n * // => '/not/a/repo'\n * ```\n */\nexport function findGitRoot(startPath: string): string {\n const fs = getFs()\n const path = getPath()\n let currentPath = startPath\n // Walk up the directory tree looking for .git\n while (true) {\n try {\n const gitPath = path.join(currentPath, '.git')\n if (fs.existsSync(gitPath)) {\n return currentPath\n }\n } catch {\n // Ignore errors and continue walking up\n }\n const parentPath = path.dirname(currentPath)\n // Stop if we've reached the root or can't go up anymore\n if (parentPath === currentPath) {\n // Return original path if no .git found\n return startPath\n }\n currentPath = parentPath\n }\n}\n\n/**\n * Parse git diff stdout output into file path array.\n *\n * Internal helper that processes raw git command output by:\n * 1. Finding git repository root from spawn cwd\n * 2. Stripping ANSI codes and splitting into lines\n * 3. Parsing porcelain format status codes if requested\n * 4. Normalizing and optionally making paths absolute\n * 5. Filtering paths based on cwd and glob options\n *\n * Git always returns paths relative to the repository root, regardless of\n * where the command was executed. This function handles the path resolution\n * correctly by finding the repo root and adjusting paths accordingly.\n *\n * @param stdout - Raw stdout from git command.\n * @param options - Git diff options for path processing.\n * @param spawnCwd - Working directory where git command was executed.\n * @returns Array of processed file paths.\n */\nfunction parseGitDiffStdout(\n stdout: string,\n options?: GitDiffOptions | undefined,\n spawnCwd?: string | undefined,\n): string[] {\n // Find git repo root from spawnCwd. Git always returns paths relative to the repo root,\n // not the cwd where it was run. So we need to find the repo root to correctly parse paths.\n const defaultRoot = spawnCwd ? findGitRoot(spawnCwd) : getCwd()\n const {\n absolute = false,\n cwd: cwdOption = defaultRoot,\n porcelain = false,\n ...matcherOptions\n } = { __proto__: null, ...options }\n // Resolve cwd to handle symlinks.\n const cwd =\n cwdOption === defaultRoot ? defaultRoot : getFs().realpathSync(cwdOption)\n const rootPath = defaultRoot\n // Split into lines without trimming to preserve leading spaces in porcelain format.\n let rawFiles = stdout\n ? stripAnsi(stdout)\n .split('\\n')\n .map(line => line.trimEnd())\n .filter(line => line)\n : []\n // Parse porcelain format: strip status codes.\n // Git status --porcelain format is: XY filename\n // where X and Y are single characters and there's a space before the filename.\n if (porcelain) {\n rawFiles = rawFiles.map(line => {\n // Status is first 2 chars, then space, then filename.\n return line.length > 3 ? line.substring(3) : line\n })\n }\n const files = absolute\n ? rawFiles.map(relPath => normalizePath(path.join(rootPath, relPath)))\n : rawFiles.map(relPath => normalizePath(relPath))\n if (cwd === rootPath) {\n return files\n }\n const relPath = normalizePath(path.relative(rootPath, cwd))\n const matcher = getGlobMatcher([`${relPath}/**`], {\n ...(matcherOptions as {\n dot?: boolean\n ignore?: string[]\n nocase?: boolean\n }),\n absolute,\n cwd: rootPath,\n } as {\n absolute?: boolean\n cwd?: string\n dot?: boolean\n ignore?: string[]\n nocase?: boolean\n })\n const filtered: string[] = []\n for (const filepath of files) {\n if (matcher(filepath)) {\n filtered.push(filepath)\n }\n }\n return filtered\n}\n\n/**\n * Get all changed files including staged, unstaged, and untracked files.\n *\n * Uses `git status --porcelain` which returns the full working tree status\n * with status codes:\n * - `M` - Modified\n * - `A` - Added\n * - `D` - Deleted\n * - `??` - Untracked\n * - `R` - Renamed\n * - `C` - Copied\n *\n * This is the most comprehensive check - captures everything that differs\n * from the last commit, including:\n * - Files modified and staged with `git add`\n * - Files modified but not staged\n * - New files not yet tracked by git\n *\n * Status codes are automatically stripped from the output.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Promise resolving to array of changed file paths.\n *\n * @example\n * ```typescript\n * // Get all changed files as relative paths\n * const files = await getChangedFiles()\n * // => ['src/foo.ts', 'src/bar.ts', 'newfile.ts']\n *\n * // Get absolute paths\n * const files = await getChangedFiles({ absolute: true })\n * // => ['/path/to/repo/src/foo.ts', ...]\n *\n * // Get changed files in specific directory\n * const files = await getChangedFiles({ cwd: '/path/to/repo/src' })\n * // => ['foo.ts', 'bar.ts']\n * ```\n */\nexport async function getChangedFiles(\n options?: GitDiffOptions | undefined,\n): Promise<string[]> {\n const args = getGitDiffSpawnArgs(options?.cwd).all\n return await innerDiff(args, {\n __proto__: null,\n ...options,\n porcelain: true,\n })\n}\n\n/**\n * Get all changed files including staged, unstaged, and untracked files.\n *\n * Synchronous version of `getChangedFiles()`. Uses `git status --porcelain`\n * which returns the full working tree status with status codes:\n * - `M` - Modified\n * - `A` - Added\n * - `D` - Deleted\n * - `??` - Untracked\n * - `R` - Renamed\n * - `C` - Copied\n *\n * This is the most comprehensive check - captures everything that differs\n * from the last commit, including:\n * - Files modified and staged with `git add`\n * - Files modified but not staged\n * - New files not yet tracked by git\n *\n * Status codes are automatically stripped from the output.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Array of changed file paths.\n *\n * @example\n * ```typescript\n * // Get all changed files as relative paths\n * const files = getChangedFilesSync()\n * // => ['src/foo.ts', 'src/bar.ts', 'newfile.ts']\n *\n * // Get absolute paths\n * const files = getChangedFilesSync({ absolute: true })\n * // => ['/path/to/repo/src/foo.ts', ...]\n *\n * // Get changed files in specific directory\n * const files = getChangedFilesSync({ cwd: '/path/to/repo/src' })\n * // => ['foo.ts', 'bar.ts']\n * ```\n */\nexport function getChangedFilesSync(\n options?: GitDiffOptions | undefined,\n): string[] {\n const args = getGitDiffSpawnArgs(options?.cwd).all\n return innerDiffSync(args, {\n __proto__: null,\n ...options,\n porcelain: true,\n })\n}\n\n/**\n * Get unstaged modified files (changes not yet staged for commit).\n *\n * Uses `git diff --name-only` which returns only unstaged modifications\n * to tracked files. Does NOT include:\n * - Untracked files (new files not added to git)\n * - Staged changes (files added with `git add`)\n *\n * This is a focused check for uncommitted changes to existing tracked files.\n * Useful for detecting work-in-progress modifications before staging.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Promise resolving to array of unstaged file paths.\n *\n * @example\n * ```typescript\n * // Get unstaged files\n * const files = await getUnstagedFiles()\n * // => ['src/foo.ts', 'src/bar.ts']\n *\n * // After staging some files\n * await spawn('git', ['add', 'src/foo.ts'])\n * const files = await getUnstagedFiles()\n * // => ['src/bar.ts'] (foo.ts no longer included)\n *\n * // Get absolute paths\n * const files = await getUnstagedFiles({ absolute: true })\n * // => ['/path/to/repo/src/bar.ts']\n * ```\n */\nexport async function getUnstagedFiles(\n options?: GitDiffOptions | undefined,\n): Promise<string[]> {\n const args = getGitDiffSpawnArgs(options?.cwd).unstaged\n return await innerDiff(args, options)\n}\n\n/**\n * Get unstaged modified files (changes not yet staged for commit).\n *\n * Synchronous version of `getUnstagedFiles()`. Uses `git diff --name-only`\n * which returns only unstaged modifications to tracked files. Does NOT include:\n * - Untracked files (new files not added to git)\n * - Staged changes (files added with `git add`)\n *\n * This is a focused check for uncommitted changes to existing tracked files.\n * Useful for detecting work-in-progress modifications before staging.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Array of unstaged file paths.\n *\n * @example\n * ```typescript\n * // Get unstaged files\n * const files = getUnstagedFilesSync()\n * // => ['src/foo.ts', 'src/bar.ts']\n *\n * // After staging some files\n * spawnSync('git', ['add', 'src/foo.ts'])\n * const files = getUnstagedFilesSync()\n * // => ['src/bar.ts'] (foo.ts no longer included)\n *\n * // Get absolute paths\n * const files = getUnstagedFilesSync({ absolute: true })\n * // => ['/path/to/repo/src/bar.ts']\n * ```\n */\nexport function getUnstagedFilesSync(\n options?: GitDiffOptions | undefined,\n): string[] {\n const args = getGitDiffSpawnArgs(options?.cwd).unstaged\n return innerDiffSync(args, options)\n}\n\n/**\n * Get staged files ready for commit (changes added with `git add`).\n *\n * Uses `git diff --cached --name-only` which returns only staged changes.\n * Does NOT include:\n * - Unstaged modifications (changes not added with `git add`)\n * - Untracked files (new files not added to git)\n *\n * This is a focused check for what will be included in the next commit.\n * Useful for validating changes before committing or running pre-commit hooks.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Promise resolving to array of staged file paths.\n *\n * @example\n * ```typescript\n * // Get currently staged files\n * const files = await getStagedFiles()\n * // => ['src/foo.ts']\n *\n * // Stage more files\n * await spawn('git', ['add', 'src/bar.ts'])\n * const files = await getStagedFiles()\n * // => ['src/foo.ts', 'src/bar.ts']\n *\n * // Get absolute paths\n * const files = await getStagedFiles({ absolute: true })\n * // => ['/path/to/repo/src/foo.ts', ...]\n * ```\n */\nexport async function getStagedFiles(\n options?: GitDiffOptions | undefined,\n): Promise<string[]> {\n const args = getGitDiffSpawnArgs(options?.cwd).staged\n return await innerDiff(args, options)\n}\n\n/**\n * Get staged files ready for commit (changes added with `git add`).\n *\n * Synchronous version of `getStagedFiles()`. Uses `git diff --cached --name-only`\n * which returns only staged changes. Does NOT include:\n * - Unstaged modifications (changes not added with `git add`)\n * - Untracked files (new files not added to git)\n *\n * This is a focused check for what will be included in the next commit.\n * Useful for validating changes before committing or running pre-commit hooks.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Array of staged file paths.\n *\n * @example\n * ```typescript\n * // Get currently staged files\n * const files = getStagedFilesSync()\n * // => ['src/foo.ts']\n *\n * // Stage more files\n * spawnSync('git', ['add', 'src/bar.ts'])\n * const files = getStagedFilesSync()\n * // => ['src/foo.ts', 'src/bar.ts']\n *\n * // Get absolute paths\n * const files = getStagedFilesSync({ absolute: true })\n * // => ['/path/to/repo/src/foo.ts', ...]\n * ```\n */\nexport function getStagedFilesSync(\n options?: GitDiffOptions | undefined,\n): string[] {\n const args = getGitDiffSpawnArgs(options?.cwd).staged\n return innerDiffSync(args, options)\n}\n\n/**\n * Check if a file or directory has any git changes.\n *\n * Checks if the given pathname has any changes including:\n * - Staged modifications (added with `git add`)\n * - Unstaged modifications (not yet staged)\n * - Untracked status (new file/directory not in git)\n *\n * For directories, returns `true` if ANY file within the directory has changes.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git status check.\n * @returns Promise resolving to `true` if path has any changes, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file is changed\n * const changed = await isChanged('src/foo.ts')\n * // => true\n *\n * // Check if directory has any changes\n * const changed = await isChanged('src/')\n * // => true (if any file in src/ is changed)\n *\n * // Check from different cwd\n * const changed = await isChanged(\n * '/path/to/repo/src/foo.ts',\n * { cwd: '/path/to/repo' }\n * )\n * ```\n */\nexport async function isChanged(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): Promise<boolean> {\n const files = await getChangedFiles({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory has any git changes.\n *\n * Synchronous version of `isChanged()`. Checks if the given pathname has\n * any changes including:\n * - Staged modifications (added with `git add`)\n * - Unstaged modifications (not yet staged)\n * - Untracked status (new file/directory not in git)\n *\n * For directories, returns `true` if ANY file within the directory has changes.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git status check.\n * @returns `true` if path has any changes, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file is changed\n * const changed = isChangedSync('src/foo.ts')\n * // => true\n *\n * // Check if directory has any changes\n * const changed = isChangedSync('src/')\n * // => true (if any file in src/ is changed)\n *\n * // Check from different cwd\n * const changed = isChangedSync(\n * '/path/to/repo/src/foo.ts',\n * { cwd: '/path/to/repo' }\n * )\n * ```\n */\nexport function isChangedSync(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): boolean {\n const files = getChangedFilesSync({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory has unstaged changes.\n *\n * Checks if the given pathname has modifications that are not yet staged\n * for commit (changes not added with `git add`). Does NOT include:\n * - Staged changes (already added with `git add`)\n * - Untracked files (new files not in git)\n *\n * For directories, returns `true` if ANY file within the directory has\n * unstaged changes.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git diff check.\n * @returns Promise resolving to `true` if path has unstaged changes, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file has unstaged changes\n * const unstaged = await isUnstaged('src/foo.ts')\n * // => true\n *\n * // After staging the file\n * await spawn('git', ['add', 'src/foo.ts'])\n * const unstaged = await isUnstaged('src/foo.ts')\n * // => false\n *\n * // Check directory\n * const unstaged = await isUnstaged('src/')\n * // => true (if any file in src/ has unstaged changes)\n * ```\n */\nexport async function isUnstaged(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): Promise<boolean> {\n const files = await getUnstagedFiles({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory has unstaged changes.\n *\n * Synchronous version of `isUnstaged()`. Checks if the given pathname has\n * modifications that are not yet staged for commit (changes not added with\n * `git add`). Does NOT include:\n * - Staged changes (already added with `git add`)\n * - Untracked files (new files not in git)\n *\n * For directories, returns `true` if ANY file within the directory has\n * unstaged changes.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git diff check.\n * @returns `true` if path has unstaged changes, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file has unstaged changes\n * const unstaged = isUnstagedSync('src/foo.ts')\n * // => true\n *\n * // After staging the file\n * spawnSync('git', ['add', 'src/foo.ts'])\n * const unstaged = isUnstagedSync('src/foo.ts')\n * // => false\n *\n * // Check directory\n * const unstaged = isUnstagedSync('src/')\n * // => true (if any file in src/ has unstaged changes)\n * ```\n */\nexport function isUnstagedSync(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): boolean {\n const files = getUnstagedFilesSync({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory is staged for commit.\n *\n * Checks if the given pathname has changes staged with `git add` that will\n * be included in the next commit. Does NOT include:\n * - Unstaged modifications (changes not added with `git add`)\n * - Untracked files (new files not in git)\n *\n * For directories, returns `true` if ANY file within the directory is staged.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git diff check.\n * @returns Promise resolving to `true` if path is staged, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file is staged\n * const staged = await isStaged('src/foo.ts')\n * // => false\n *\n * // Stage the file\n * await spawn('git', ['add', 'src/foo.ts'])\n * const staged = await isStaged('src/foo.ts')\n * // => true\n *\n * // Check directory\n * const staged = await isStaged('src/')\n * // => true (if any file in src/ is staged)\n * ```\n */\nexport async function isStaged(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): Promise<boolean> {\n const files = await getStagedFiles({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory is staged for commit.\n *\n * Synchronous version of `isStaged()`. Checks if the given pathname has\n * changes staged with `git add` that will be included in the next commit.\n * Does NOT include:\n * - Unstaged modifications (changes not added with `git add`)\n * - Untracked files (new files not in git)\n *\n * For directories, returns `true` if ANY file within the directory is staged.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git diff check.\n * @returns `true` if path is staged, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file is staged\n * const staged = isStagedSync('src/foo.ts')\n * // => false\n *\n * // Stage the file\n * spawnSync('git', ['add', 'src/foo.ts'])\n * const staged = isStagedSync('src/foo.ts')\n * // => true\n *\n * // Check directory\n * const staged = isStagedSync('src/')\n * // => true (if any file in src/ is staged)\n * ```\n */\nexport function isStagedSync(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): boolean {\n const files = getStagedFilesSync({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAiB;AAEjB,mBAA+B;AAC/B,kBAA8B;AAC9B,mBAAiC;AACjC,qBAA0B;AAqH1B,MAAM,eAAe,oBAAI,IAAsB;AAE/C,IAAI;AAAA;AAgBJ,SAAS,QAAQ;AACf,MAAI,QAAQ,QAAW;AAGrB,UAAoB,QAAQ,SAAS;AAAA,EACvC;AACA,SAAO;AACT;AAEA,IAAI;AAAA;AAgBJ,SAAS,UAAU;AACjB,MAAI,UAAU,QAAW;AACvB,YAAsB,QAAQ,WAAW;AAAA,EAC3C;AACA,SAAO;AACT;AAiBA,SAAS,aAAqB;AAC5B,SAAO;AACT;AAkBA,SAAS,SAAiB;AACxB,UAAO,sBAAM,GAAE,aAAa,QAAQ,IAAI,CAAC;AAC3C;AAgBA,SAAS,oBAAoB,KAA4C;AACvE,QAAM,cAAc,OAAM,sBAAM,GAAE,aAAa,GAAG,IAAI,OAAO;AAC7D,SAAO;AAAA,IACL,KAAK;AAAA,MACH,WAAW;AAAA,MACX,CAAC,UAAU,aAAa;AAAA,MACxB;AAAA,QACE,KAAK;AAAA,QACL,OAAO
|
|
4
|
+
"sourcesContent": ["import path from 'node:path'\n\nimport { WIN32 } from '#constants/platform'\nimport { getGlobMatcher } from './globs'\nimport { normalizePath } from './path'\nimport { spawn, spawnSync } from './spawn'\nimport { stripAnsi } from './strings'\n\n/**\n * Options for git diff operations.\n *\n * Controls how git diff results are processed and returned.\n *\n * @example\n * ```typescript\n * // Get absolute file paths\n * const files = await getChangedFiles({ absolute: true })\n * // => ['/path/to/repo/src/file.ts']\n *\n * // Get relative paths with caching disabled\n * const files = await getChangedFiles({ cache: false })\n * // => ['src/file.ts']\n *\n * // Get files from specific directory\n * const files = await getChangedFiles({ cwd: '/path/to/repo/src' })\n * ```\n */\nexport interface GitDiffOptions {\n /**\n * Return absolute file paths instead of relative paths.\n *\n * @default false\n */\n absolute?: boolean | undefined\n /**\n * Cache git diff results to avoid repeated git subprocess calls.\n *\n * Caching is keyed by the git command and options used, so different\n * option combinations maintain separate cache entries.\n *\n * @default true\n */\n cache?: boolean | undefined\n /**\n * Working directory for git operations.\n *\n * Git operations will be run from this directory, and returned paths\n * will be relative to the git repository root. Symlinks are resolved\n * using `fs.realpathSync()`.\n *\n * @default process.cwd()\n */\n cwd?: string | undefined\n /**\n * Parse git porcelain format output (status codes like `M`, `A`, `??`).\n *\n * When `true`, strips the two-character status code and space from the\n * beginning of each line. Automatically enabled for `getChangedFiles()`.\n *\n * @default false\n */\n porcelain?: boolean | undefined\n /**\n * Return results as a `Set` instead of an array.\n *\n * @default false\n */\n asSet?: boolean | undefined\n /**\n * Additional options passed to glob matcher.\n *\n * Supports options like `dot`, `ignore`, `nocase` for filtering results.\n */\n [key: string]: unknown\n}\n\n/**\n * Options for filtering packages by git changes.\n *\n * Used to determine which packages in a monorepo have changed files.\n *\n * @example\n * ```typescript\n * // Filter packages with changes\n * const changed = filterPackagesByChanges(packages)\n *\n * // Force include all packages\n * const all = filterPackagesByChanges(packages, { force: true })\n *\n * // Use custom package key\n * const changed = filterPackagesByChanges(\n * packages,\n * { packageKey: 'directory' }\n * )\n * ```\n */\nexport interface FilterPackagesByChangesOptions {\n /**\n * Force include all packages regardless of changes.\n *\n * @default false\n */\n force?: boolean | undefined\n /**\n * Key to access package path in package objects.\n *\n * @default 'path'\n */\n packageKey?: string | undefined\n /**\n * Additional options for filtering.\n */\n [key: string]: unknown\n}\n\ntype SpawnArgs = [string, string[], Record<string, unknown>]\n\ninterface GitDiffSpawnArgs {\n all: SpawnArgs\n unstaged: SpawnArgs\n staged: SpawnArgs\n}\n\nconst gitDiffCache = new Map<string, string[]>()\n\nlet _fs: typeof import('fs') | undefined\n/**\n * Lazily load the `fs` module to avoid Webpack errors.\n *\n * Uses non-`node:` prefixed require internally to prevent Webpack from\n * attempting to bundle Node.js built-in modules.\n *\n * @returns The Node.js `fs` module.\n *\n * @example\n * ```typescript\n * const fs = getFs()\n * const exists = fs.existsSync('/path/to/file')\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getFs() {\n if (_fs === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _fs = /*@__PURE__*/ require('node:fs')\n }\n return _fs as typeof import('fs')\n}\n\nlet _path: typeof import('path') | undefined\n/**\n * Lazily load the `path` module to avoid Webpack errors.\n *\n * Uses non-`node:` prefixed require internally to prevent Webpack from\n * attempting to bundle Node.js built-in modules.\n *\n * @returns The Node.js `path` module.\n *\n * @example\n * ```typescript\n * const path = getPath()\n * const joined = path.join('/foo', 'bar')\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getPath() {\n if (_path === undefined) {\n _path = /*@__PURE__*/ require('node:path')\n }\n return _path as typeof import('path')\n}\n\n/**\n * Get the git executable path.\n *\n * Currently always returns `'git'`, relying on the system PATH to resolve\n * the git binary location. This may be extended in the future to support\n * custom git paths.\n *\n * @returns The git executable name or path.\n *\n * @example\n * ```typescript\n * const git = getGitPath()\n * // => 'git'\n * ```\n */\nfunction getGitPath(): string {\n return 'git'\n}\n\n/**\n * Get the current working directory for git operations.\n *\n * Returns the real path to handle symlinks correctly. This is important\n * because symlinked directories like `/tmp -> /private/tmp` can cause\n * path mismatches when comparing git output.\n *\n * @returns The resolved real path of `process.cwd()`.\n *\n * @example\n * ```typescript\n * const cwd = getCwd()\n * // In /tmp (symlink to /private/tmp):\n * // => '/private/tmp'\n * ```\n */\nfunction getCwd(): string {\n return getFs().realpathSync(process.cwd())\n}\n\n/**\n * Get spawn arguments for different git diff operations.\n *\n * Prepares argument arrays for `spawn()`/`spawnSync()` calls that retrieve:\n * - `all`: All changed files (staged, unstaged, untracked) via `git status --porcelain`\n * - `unstaged`: Unstaged modifications via `git diff --name-only`\n * - `staged`: Staged changes via `git diff --cached --name-only`\n *\n * Automatically resolves symlinks in the provided `cwd` and enables shell\n * mode on Windows for proper command execution.\n *\n * @param cwd - Working directory for git operations, defaults to `process.cwd()`.\n * @returns Object containing spawn arguments for all, unstaged, and staged operations.\n */\nfunction getGitDiffSpawnArgs(cwd?: string | undefined): GitDiffSpawnArgs {\n const resolvedCwd = cwd ? getFs().realpathSync(cwd) : getCwd()\n return {\n all: [\n getGitPath(),\n ['status', '--porcelain'],\n {\n cwd: resolvedCwd,\n shell: WIN32,\n },\n ],\n unstaged: [\n getGitPath(),\n ['diff', '--name-only'],\n {\n cwd: resolvedCwd,\n },\n ],\n staged: [\n getGitPath(),\n ['diff', '--cached', '--name-only'],\n {\n cwd: resolvedCwd,\n shell: WIN32,\n },\n ],\n }\n}\n\n/**\n * Execute git diff command asynchronously and parse results.\n *\n * Internal helper for async git operations. Handles caching, command execution,\n * and result parsing. Returns empty array on git command failure.\n *\n * @param args - Spawn arguments tuple `[command, args, options]`.\n * @param options - Git diff options for caching and parsing.\n * @returns Promise resolving to array of file paths.\n */\nasync function innerDiff(\n args: SpawnArgs,\n options?: GitDiffOptions | undefined,\n): Promise<string[]> {\n const { cache = true, ...parseOptions } = { __proto__: null, ...options }\n const cacheKey = cache ? JSON.stringify({ args, parseOptions }) : undefined\n if (cache && cacheKey) {\n const result = gitDiffCache.get(cacheKey)\n if (result) {\n return result\n }\n }\n let result: string[]\n try {\n // Use stdioString: false to get raw Buffer, then convert ourselves to preserve exact output.\n const spawnResult = await spawn(args[0], args[1], {\n ...args[2],\n stdioString: false,\n })\n const stdout = Buffer.isBuffer(spawnResult.stdout)\n ? spawnResult.stdout.toString('utf8')\n : String(spawnResult.stdout)\n // Extract spawn cwd from args to pass to parser\n const spawnCwd =\n typeof args[2]['cwd'] === 'string' ? args[2]['cwd'] : undefined\n result = parseGitDiffStdout(stdout, parseOptions, spawnCwd)\n } catch {\n return []\n }\n if (cache && cacheKey) {\n gitDiffCache.set(cacheKey, result)\n }\n return result\n}\n\n/**\n * Execute git diff command synchronously and parse results.\n *\n * Internal helper for sync git operations. Handles caching, command execution,\n * and result parsing. Returns empty array on git command failure.\n *\n * @param args - Spawn arguments tuple `[command, args, options]`.\n * @param options - Git diff options for caching and parsing.\n * @returns Array of file paths.\n */\nfunction innerDiffSync(\n args: SpawnArgs,\n options?: GitDiffOptions | undefined,\n): string[] {\n const { cache = true, ...parseOptions } = { __proto__: null, ...options }\n const cacheKey = cache ? JSON.stringify({ args, parseOptions }) : undefined\n if (cache && cacheKey) {\n const result = gitDiffCache.get(cacheKey)\n if (result) {\n return result\n }\n }\n let result: string[]\n try {\n // Use stdioString: false to get raw Buffer, then convert ourselves to preserve exact output.\n const spawnResult = spawnSync(args[0], args[1], {\n ...args[2],\n stdioString: false,\n })\n const stdout = Buffer.isBuffer(spawnResult.stdout)\n ? spawnResult.stdout.toString('utf8')\n : String(spawnResult.stdout)\n // Extract spawn cwd from args to pass to parser\n const spawnCwd =\n typeof args[2]['cwd'] === 'string' ? args[2]['cwd'] : undefined\n result = parseGitDiffStdout(stdout, parseOptions, spawnCwd)\n } catch {\n return []\n }\n if (cache && cacheKey) {\n gitDiffCache.set(cacheKey, result)\n }\n return result\n}\n\n/**\n * Find git repository root by walking up from the given directory.\n *\n * Searches for a `.git` directory or file by traversing parent directories\n * upward until found or filesystem root is reached. Returns the original path\n * if no git repository is found.\n *\n * This function is exported primarily for testing purposes.\n *\n * @param startPath - Directory path to start searching from.\n * @returns Git repository root path, or `startPath` if not found.\n *\n * @example\n * ```typescript\n * const root = findGitRoot('/path/to/repo/src/subdir')\n * // => '/path/to/repo'\n *\n * const notFound = findGitRoot('/not/a/repo')\n * // => '/not/a/repo'\n * ```\n */\nexport function findGitRoot(startPath: string): string {\n const fs = getFs()\n const path = getPath()\n let currentPath = startPath\n // Walk up the directory tree looking for .git\n while (true) {\n try {\n const gitPath = path.join(currentPath, '.git')\n if (fs.existsSync(gitPath)) {\n return currentPath\n }\n } catch {\n // Ignore errors and continue walking up\n }\n const parentPath = path.dirname(currentPath)\n // Stop if we've reached the root or can't go up anymore\n if (parentPath === currentPath) {\n // Return original path if no .git found\n return startPath\n }\n currentPath = parentPath\n }\n}\n\n/**\n * Parse git diff stdout output into file path array.\n *\n * Internal helper that processes raw git command output by:\n * 1. Finding git repository root from spawn cwd\n * 2. Stripping ANSI codes and splitting into lines\n * 3. Parsing porcelain format status codes if requested\n * 4. Normalizing and optionally making paths absolute\n * 5. Filtering paths based on cwd and glob options\n *\n * Git always returns paths relative to the repository root, regardless of\n * where the command was executed. This function handles the path resolution\n * correctly by finding the repo root and adjusting paths accordingly.\n *\n * @param stdout - Raw stdout from git command.\n * @param options - Git diff options for path processing.\n * @param spawnCwd - Working directory where git command was executed.\n * @returns Array of processed file paths.\n */\nfunction parseGitDiffStdout(\n stdout: string,\n options?: GitDiffOptions | undefined,\n spawnCwd?: string | undefined,\n): string[] {\n // Find git repo root from spawnCwd. Git always returns paths relative to the repo root,\n // not the cwd where it was run. So we need to find the repo root to correctly parse paths.\n const defaultRoot = spawnCwd ? findGitRoot(spawnCwd) : getCwd()\n const {\n absolute = false,\n cwd: cwdOption = defaultRoot,\n porcelain = false,\n ...matcherOptions\n } = { __proto__: null, ...options }\n // Resolve cwd to handle symlinks.\n const cwd =\n cwdOption === defaultRoot ? defaultRoot : getFs().realpathSync(cwdOption)\n const rootPath = defaultRoot\n // Split into lines without trimming to preserve leading spaces in porcelain format.\n let rawFiles = stdout\n ? stripAnsi(stdout)\n .split('\\n')\n .map(line => line.trimEnd())\n .filter(line => line)\n : []\n // Parse porcelain format: strip status codes.\n // Git status --porcelain format is: XY filename\n // where X and Y are single characters and there's a space before the filename.\n if (porcelain) {\n rawFiles = rawFiles.map(line => {\n // Status is first 2 chars, then space, then filename.\n return line.length > 3 ? line.substring(3) : line\n })\n }\n const files = absolute\n ? rawFiles.map(relPath => normalizePath(path.join(rootPath, relPath)))\n : rawFiles.map(relPath => normalizePath(relPath))\n if (cwd === rootPath) {\n return files\n }\n const relPath = normalizePath(path.relative(rootPath, cwd))\n const matcher = getGlobMatcher([`${relPath}/**`], {\n ...(matcherOptions as {\n dot?: boolean\n ignore?: string[]\n nocase?: boolean\n }),\n absolute,\n cwd: rootPath,\n } as {\n absolute?: boolean\n cwd?: string\n dot?: boolean\n ignore?: string[]\n nocase?: boolean\n })\n const filtered: string[] = []\n for (const filepath of files) {\n if (matcher(filepath)) {\n filtered.push(filepath)\n }\n }\n return filtered\n}\n\n/**\n * Get all changed files including staged, unstaged, and untracked files.\n *\n * Uses `git status --porcelain` which returns the full working tree status\n * with status codes:\n * - `M` - Modified\n * - `A` - Added\n * - `D` - Deleted\n * - `??` - Untracked\n * - `R` - Renamed\n * - `C` - Copied\n *\n * This is the most comprehensive check - captures everything that differs\n * from the last commit, including:\n * - Files modified and staged with `git add`\n * - Files modified but not staged\n * - New files not yet tracked by git\n *\n * Status codes are automatically stripped from the output.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Promise resolving to array of changed file paths.\n *\n * @example\n * ```typescript\n * // Get all changed files as relative paths\n * const files = await getChangedFiles()\n * // => ['src/foo.ts', 'src/bar.ts', 'newfile.ts']\n *\n * // Get absolute paths\n * const files = await getChangedFiles({ absolute: true })\n * // => ['/path/to/repo/src/foo.ts', ...]\n *\n * // Get changed files in specific directory\n * const files = await getChangedFiles({ cwd: '/path/to/repo/src' })\n * // => ['foo.ts', 'bar.ts']\n * ```\n */\nexport async function getChangedFiles(\n options?: GitDiffOptions | undefined,\n): Promise<string[]> {\n const args = getGitDiffSpawnArgs(options?.cwd).all\n return await innerDiff(args, {\n __proto__: null,\n ...options,\n porcelain: true,\n })\n}\n\n/**\n * Get all changed files including staged, unstaged, and untracked files.\n *\n * Synchronous version of `getChangedFiles()`. Uses `git status --porcelain`\n * which returns the full working tree status with status codes:\n * - `M` - Modified\n * - `A` - Added\n * - `D` - Deleted\n * - `??` - Untracked\n * - `R` - Renamed\n * - `C` - Copied\n *\n * This is the most comprehensive check - captures everything that differs\n * from the last commit, including:\n * - Files modified and staged with `git add`\n * - Files modified but not staged\n * - New files not yet tracked by git\n *\n * Status codes are automatically stripped from the output.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Array of changed file paths.\n *\n * @example\n * ```typescript\n * // Get all changed files as relative paths\n * const files = getChangedFilesSync()\n * // => ['src/foo.ts', 'src/bar.ts', 'newfile.ts']\n *\n * // Get absolute paths\n * const files = getChangedFilesSync({ absolute: true })\n * // => ['/path/to/repo/src/foo.ts', ...]\n *\n * // Get changed files in specific directory\n * const files = getChangedFilesSync({ cwd: '/path/to/repo/src' })\n * // => ['foo.ts', 'bar.ts']\n * ```\n */\nexport function getChangedFilesSync(\n options?: GitDiffOptions | undefined,\n): string[] {\n const args = getGitDiffSpawnArgs(options?.cwd).all\n return innerDiffSync(args, {\n __proto__: null,\n ...options,\n porcelain: true,\n })\n}\n\n/**\n * Get unstaged modified files (changes not yet staged for commit).\n *\n * Uses `git diff --name-only` which returns only unstaged modifications\n * to tracked files. Does NOT include:\n * - Untracked files (new files not added to git)\n * - Staged changes (files added with `git add`)\n *\n * This is a focused check for uncommitted changes to existing tracked files.\n * Useful for detecting work-in-progress modifications before staging.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Promise resolving to array of unstaged file paths.\n *\n * @example\n * ```typescript\n * // Get unstaged files\n * const files = await getUnstagedFiles()\n * // => ['src/foo.ts', 'src/bar.ts']\n *\n * // After staging some files\n * await spawn('git', ['add', 'src/foo.ts'])\n * const files = await getUnstagedFiles()\n * // => ['src/bar.ts'] (foo.ts no longer included)\n *\n * // Get absolute paths\n * const files = await getUnstagedFiles({ absolute: true })\n * // => ['/path/to/repo/src/bar.ts']\n * ```\n */\nexport async function getUnstagedFiles(\n options?: GitDiffOptions | undefined,\n): Promise<string[]> {\n const args = getGitDiffSpawnArgs(options?.cwd).unstaged\n return await innerDiff(args, options)\n}\n\n/**\n * Get unstaged modified files (changes not yet staged for commit).\n *\n * Synchronous version of `getUnstagedFiles()`. Uses `git diff --name-only`\n * which returns only unstaged modifications to tracked files. Does NOT include:\n * - Untracked files (new files not added to git)\n * - Staged changes (files added with `git add`)\n *\n * This is a focused check for uncommitted changes to existing tracked files.\n * Useful for detecting work-in-progress modifications before staging.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Array of unstaged file paths.\n *\n * @example\n * ```typescript\n * // Get unstaged files\n * const files = getUnstagedFilesSync()\n * // => ['src/foo.ts', 'src/bar.ts']\n *\n * // After staging some files\n * spawnSync('git', ['add', 'src/foo.ts'])\n * const files = getUnstagedFilesSync()\n * // => ['src/bar.ts'] (foo.ts no longer included)\n *\n * // Get absolute paths\n * const files = getUnstagedFilesSync({ absolute: true })\n * // => ['/path/to/repo/src/bar.ts']\n * ```\n */\nexport function getUnstagedFilesSync(\n options?: GitDiffOptions | undefined,\n): string[] {\n const args = getGitDiffSpawnArgs(options?.cwd).unstaged\n return innerDiffSync(args, options)\n}\n\n/**\n * Get staged files ready for commit (changes added with `git add`).\n *\n * Uses `git diff --cached --name-only` which returns only staged changes.\n * Does NOT include:\n * - Unstaged modifications (changes not added with `git add`)\n * - Untracked files (new files not added to git)\n *\n * This is a focused check for what will be included in the next commit.\n * Useful for validating changes before committing or running pre-commit hooks.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Promise resolving to array of staged file paths.\n *\n * @example\n * ```typescript\n * // Get currently staged files\n * const files = await getStagedFiles()\n * // => ['src/foo.ts']\n *\n * // Stage more files\n * await spawn('git', ['add', 'src/bar.ts'])\n * const files = await getStagedFiles()\n * // => ['src/foo.ts', 'src/bar.ts']\n *\n * // Get absolute paths\n * const files = await getStagedFiles({ absolute: true })\n * // => ['/path/to/repo/src/foo.ts', ...]\n * ```\n */\nexport async function getStagedFiles(\n options?: GitDiffOptions | undefined,\n): Promise<string[]> {\n const args = getGitDiffSpawnArgs(options?.cwd).staged\n return await innerDiff(args, options)\n}\n\n/**\n * Get staged files ready for commit (changes added with `git add`).\n *\n * Synchronous version of `getStagedFiles()`. Uses `git diff --cached --name-only`\n * which returns only staged changes. Does NOT include:\n * - Unstaged modifications (changes not added with `git add`)\n * - Untracked files (new files not added to git)\n *\n * This is a focused check for what will be included in the next commit.\n * Useful for validating changes before committing or running pre-commit hooks.\n *\n * @param options - Options controlling path format and filtering.\n * @returns Array of staged file paths.\n *\n * @example\n * ```typescript\n * // Get currently staged files\n * const files = getStagedFilesSync()\n * // => ['src/foo.ts']\n *\n * // Stage more files\n * spawnSync('git', ['add', 'src/bar.ts'])\n * const files = getStagedFilesSync()\n * // => ['src/foo.ts', 'src/bar.ts']\n *\n * // Get absolute paths\n * const files = getStagedFilesSync({ absolute: true })\n * // => ['/path/to/repo/src/foo.ts', ...]\n * ```\n */\nexport function getStagedFilesSync(\n options?: GitDiffOptions | undefined,\n): string[] {\n const args = getGitDiffSpawnArgs(options?.cwd).staged\n return innerDiffSync(args, options)\n}\n\n/**\n * Check if a file or directory has any git changes.\n *\n * Checks if the given pathname has any changes including:\n * - Staged modifications (added with `git add`)\n * - Unstaged modifications (not yet staged)\n * - Untracked status (new file/directory not in git)\n *\n * For directories, returns `true` if ANY file within the directory has changes.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git status check.\n * @returns Promise resolving to `true` if path has any changes, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file is changed\n * const changed = await isChanged('src/foo.ts')\n * // => true\n *\n * // Check if directory has any changes\n * const changed = await isChanged('src/')\n * // => true (if any file in src/ is changed)\n *\n * // Check from different cwd\n * const changed = await isChanged(\n * '/path/to/repo/src/foo.ts',\n * { cwd: '/path/to/repo' }\n * )\n * ```\n */\nexport async function isChanged(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): Promise<boolean> {\n const files = await getChangedFiles({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory has any git changes.\n *\n * Synchronous version of `isChanged()`. Checks if the given pathname has\n * any changes including:\n * - Staged modifications (added with `git add`)\n * - Unstaged modifications (not yet staged)\n * - Untracked status (new file/directory not in git)\n *\n * For directories, returns `true` if ANY file within the directory has changes.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git status check.\n * @returns `true` if path has any changes, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file is changed\n * const changed = isChangedSync('src/foo.ts')\n * // => true\n *\n * // Check if directory has any changes\n * const changed = isChangedSync('src/')\n * // => true (if any file in src/ is changed)\n *\n * // Check from different cwd\n * const changed = isChangedSync(\n * '/path/to/repo/src/foo.ts',\n * { cwd: '/path/to/repo' }\n * )\n * ```\n */\nexport function isChangedSync(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): boolean {\n const files = getChangedFilesSync({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory has unstaged changes.\n *\n * Checks if the given pathname has modifications that are not yet staged\n * for commit (changes not added with `git add`). Does NOT include:\n * - Staged changes (already added with `git add`)\n * - Untracked files (new files not in git)\n *\n * For directories, returns `true` if ANY file within the directory has\n * unstaged changes.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git diff check.\n * @returns Promise resolving to `true` if path has unstaged changes, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file has unstaged changes\n * const unstaged = await isUnstaged('src/foo.ts')\n * // => true\n *\n * // After staging the file\n * await spawn('git', ['add', 'src/foo.ts'])\n * const unstaged = await isUnstaged('src/foo.ts')\n * // => false\n *\n * // Check directory\n * const unstaged = await isUnstaged('src/')\n * // => true (if any file in src/ has unstaged changes)\n * ```\n */\nexport async function isUnstaged(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): Promise<boolean> {\n const files = await getUnstagedFiles({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory has unstaged changes.\n *\n * Synchronous version of `isUnstaged()`. Checks if the given pathname has\n * modifications that are not yet staged for commit (changes not added with\n * `git add`). Does NOT include:\n * - Staged changes (already added with `git add`)\n * - Untracked files (new files not in git)\n *\n * For directories, returns `true` if ANY file within the directory has\n * unstaged changes.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git diff check.\n * @returns `true` if path has unstaged changes, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file has unstaged changes\n * const unstaged = isUnstagedSync('src/foo.ts')\n * // => true\n *\n * // After staging the file\n * spawnSync('git', ['add', 'src/foo.ts'])\n * const unstaged = isUnstagedSync('src/foo.ts')\n * // => false\n *\n * // Check directory\n * const unstaged = isUnstagedSync('src/')\n * // => true (if any file in src/ has unstaged changes)\n * ```\n */\nexport function isUnstagedSync(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): boolean {\n const files = getUnstagedFilesSync({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory is staged for commit.\n *\n * Checks if the given pathname has changes staged with `git add` that will\n * be included in the next commit. Does NOT include:\n * - Unstaged modifications (changes not added with `git add`)\n * - Untracked files (new files not in git)\n *\n * For directories, returns `true` if ANY file within the directory is staged.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git diff check.\n * @returns Promise resolving to `true` if path is staged, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file is staged\n * const staged = await isStaged('src/foo.ts')\n * // => false\n *\n * // Stage the file\n * await spawn('git', ['add', 'src/foo.ts'])\n * const staged = await isStaged('src/foo.ts')\n * // => true\n *\n * // Check directory\n * const staged = await isStaged('src/')\n * // => true (if any file in src/ is staged)\n * ```\n */\nexport async function isStaged(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): Promise<boolean> {\n const files = await getStagedFiles({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n\n/**\n * Check if a file or directory is staged for commit.\n *\n * Synchronous version of `isStaged()`. Checks if the given pathname has\n * changes staged with `git add` that will be included in the next commit.\n * Does NOT include:\n * - Unstaged modifications (changes not added with `git add`)\n * - Untracked files (new files not in git)\n *\n * For directories, returns `true` if ANY file within the directory is staged.\n *\n * Symlinks in the pathname and cwd are automatically resolved using\n * `fs.realpathSync()` before comparison.\n *\n * @param pathname - File or directory path to check.\n * @param options - Options for the git diff check.\n * @returns `true` if path is staged, `false` otherwise.\n *\n * @example\n * ```typescript\n * // Check if file is staged\n * const staged = isStagedSync('src/foo.ts')\n * // => false\n *\n * // Stage the file\n * spawnSync('git', ['add', 'src/foo.ts'])\n * const staged = isStagedSync('src/foo.ts')\n * // => true\n *\n * // Check directory\n * const staged = isStagedSync('src/')\n * // => true (if any file in src/ is staged)\n * ```\n */\nexport function isStagedSync(\n pathname: string,\n options?: GitDiffOptions | undefined,\n): boolean {\n const files = getStagedFilesSync({\n __proto__: null,\n ...options,\n absolute: false,\n })\n // Resolve pathname to handle symlinks before computing relative path.\n const resolvedPathname = getFs().realpathSync(pathname)\n const baseCwd = options?.cwd ? getFs().realpathSync(options['cwd']) : getCwd()\n const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))\n return files.includes(relativePath)\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAiB;AAEjB,sBAAsB;AACtB,mBAA+B;AAC/B,kBAA8B;AAC9B,mBAAiC;AACjC,qBAA0B;AAqH1B,MAAM,eAAe,oBAAI,IAAsB;AAE/C,IAAI;AAAA;AAgBJ,SAAS,QAAQ;AACf,MAAI,QAAQ,QAAW;AAGrB,UAAoB,QAAQ,SAAS;AAAA,EACvC;AACA,SAAO;AACT;AAEA,IAAI;AAAA;AAgBJ,SAAS,UAAU;AACjB,MAAI,UAAU,QAAW;AACvB,YAAsB,QAAQ,WAAW;AAAA,EAC3C;AACA,SAAO;AACT;AAiBA,SAAS,aAAqB;AAC5B,SAAO;AACT;AAkBA,SAAS,SAAiB;AACxB,UAAO,sBAAM,GAAE,aAAa,QAAQ,IAAI,CAAC;AAC3C;AAgBA,SAAS,oBAAoB,KAA4C;AACvE,QAAM,cAAc,OAAM,sBAAM,GAAE,aAAa,GAAG,IAAI,OAAO;AAC7D,SAAO;AAAA,IACL,KAAK;AAAA,MACH,WAAW;AAAA,MACX,CAAC,UAAU,aAAa;AAAA,MACxB;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,WAAW;AAAA,MACX,CAAC,QAAQ,aAAa;AAAA,MACtB;AAAA,QACE,KAAK;AAAA,MACP;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,CAAC,QAAQ,YAAY,aAAa;AAAA,MAClC;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;AAYA,eAAe,UACb,MACA,SACmB;AACnB,QAAM,EAAE,QAAQ,MAAM,GAAG,aAAa,IAAI,EAAE,WAAW,MAAM,GAAG,QAAQ;AACxE,QAAM,WAAW,QAAQ,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC,IAAI;AAClE,MAAI,SAAS,UAAU;AACrB,UAAMA,UAAS,aAAa,IAAI,QAAQ;AACxC,QAAIA,SAAQ;AACV,aAAOA;AAAA,IACT;AAAA,EACF;AACA,MAAI;AACJ,MAAI;AAEF,UAAM,cAAc,UAAM,oBAAM,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG;AAAA,MAChD,GAAG,KAAK,CAAC;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AACD,UAAM,SAAS,OAAO,SAAS,YAAY,MAAM,IAC7C,YAAY,OAAO,SAAS,MAAM,IAClC,OAAO,YAAY,MAAM;AAE7B,UAAM,WACJ,OAAO,KAAK,CAAC,EAAE,KAAK,MAAM,WAAW,KAAK,CAAC,EAAE,KAAK,IAAI;AACxD,aAAS,mBAAmB,QAAQ,cAAc,QAAQ;AAAA,EAC5D,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI,SAAS,UAAU;AACrB,iBAAa,IAAI,UAAU,MAAM;AAAA,EACnC;AACA,SAAO;AACT;AAYA,SAAS,cACP,MACA,SACU;AACV,QAAM,EAAE,QAAQ,MAAM,GAAG,aAAa,IAAI,EAAE,WAAW,MAAM,GAAG,QAAQ;AACxE,QAAM,WAAW,QAAQ,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC,IAAI;AAClE,MAAI,SAAS,UAAU;AACrB,UAAMA,UAAS,aAAa,IAAI,QAAQ;AACxC,QAAIA,SAAQ;AACV,aAAOA;AAAA,IACT;AAAA,EACF;AACA,MAAI;AACJ,MAAI;AAEF,UAAM,kBAAc,wBAAU,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG;AAAA,MAC9C,GAAG,KAAK,CAAC;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AACD,UAAM,SAAS,OAAO,SAAS,YAAY,MAAM,IAC7C,YAAY,OAAO,SAAS,MAAM,IAClC,OAAO,YAAY,MAAM;AAE7B,UAAM,WACJ,OAAO,KAAK,CAAC,EAAE,KAAK,MAAM,WAAW,KAAK,CAAC,EAAE,KAAK,IAAI;AACxD,aAAS,mBAAmB,QAAQ,cAAc,QAAQ;AAAA,EAC5D,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI,SAAS,UAAU;AACrB,iBAAa,IAAI,UAAU,MAAM;AAAA,EACnC;AACA,SAAO;AACT;AAuBO,SAAS,YAAY,WAA2B;AACrD,QAAM,KAAK,sBAAM;AACjB,QAAMC,QAAO,wBAAQ;AACrB,MAAI,cAAc;AAElB,SAAO,MAAM;AACX,QAAI;AACF,YAAM,UAAUA,MAAK,KAAK,aAAa,MAAM;AAC7C,UAAI,GAAG,WAAW,OAAO,GAAG;AAC1B,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AACA,UAAM,aAAaA,MAAK,QAAQ,WAAW;AAE3C,QAAI,eAAe,aAAa;AAE9B,aAAO;AAAA,IACT;AACA,kBAAc;AAAA,EAChB;AACF;AAqBA,SAAS,mBACP,QACA,SACA,UACU;AAGV,QAAM,cAAc,WAAW,YAAY,QAAQ,IAAI,OAAO;AAC9D,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,KAAK,YAAY;AAAA,IACjB,YAAY;AAAA,IACZ,GAAG;AAAA,EACL,IAAI,EAAE,WAAW,MAAM,GAAG,QAAQ;AAElC,QAAM,MACJ,cAAc,cAAc,eAAc,sBAAM,GAAE,aAAa,SAAS;AAC1E,QAAM,WAAW;AAEjB,MAAI,WAAW,aACX,0BAAU,MAAM,EACb,MAAM,IAAI,EACV,IAAI,UAAQ,KAAK,QAAQ,CAAC,EAC1B,OAAO,UAAQ,IAAI,IACtB,CAAC;AAIL,MAAI,WAAW;AACb,eAAW,SAAS,IAAI,UAAQ;AAE9B,aAAO,KAAK,SAAS,IAAI,KAAK,UAAU,CAAC,IAAI;AAAA,IAC/C,CAAC;AAAA,EACH;AACA,QAAM,QAAQ,WACV,SAAS,IAAI,CAAAC,iBAAW,2BAAc,iBAAAD,QAAK,KAAK,UAAUC,QAAO,CAAC,CAAC,IACnE,SAAS,IAAI,CAAAA,iBAAW,2BAAcA,QAAO,CAAC;AAClD,MAAI,QAAQ,UAAU;AACpB,WAAO;AAAA,EACT;AACA,QAAM,cAAU,2BAAc,iBAAAD,QAAK,SAAS,UAAU,GAAG,CAAC;AAC1D,QAAM,cAAU,6BAAe,CAAC,GAAG,OAAO,KAAK,GAAG;AAAA,IAChD,GAAI;AAAA,IAKJ;AAAA,IACA,KAAK;AAAA,EACP,CAMC;AACD,QAAM,WAAqB,CAAC;AAC5B,aAAW,YAAY,OAAO;AAC5B,QAAI,QAAQ,QAAQ,GAAG;AACrB,eAAS,KAAK,QAAQ;AAAA,IACxB;AAAA,EACF;AACA,SAAO;AACT;AAwCA,eAAsB,gBACpB,SACmB;AACnB,QAAM,OAAO,oBAAoB,SAAS,GAAG,EAAE;AAC/C,SAAO,MAAM,UAAU,MAAM;AAAA,IAC3B,WAAW;AAAA,IACX,GAAG;AAAA,IACH,WAAW;AAAA,EACb,CAAC;AACH;AAwCO,SAAS,oBACd,SACU;AACV,QAAM,OAAO,oBAAoB,SAAS,GAAG,EAAE;AAC/C,SAAO,cAAc,MAAM;AAAA,IACzB,WAAW;AAAA,IACX,GAAG;AAAA,IACH,WAAW;AAAA,EACb,CAAC;AACH;AAgCA,eAAsB,iBACpB,SACmB;AACnB,QAAM,OAAO,oBAAoB,SAAS,GAAG,EAAE;AAC/C,SAAO,MAAM,UAAU,MAAM,OAAO;AACtC;AAgCO,SAAS,qBACd,SACU;AACV,QAAM,OAAO,oBAAoB,SAAS,GAAG,EAAE;AAC/C,SAAO,cAAc,MAAM,OAAO;AACpC;AAgCA,eAAsB,eACpB,SACmB;AACnB,QAAM,OAAO,oBAAoB,SAAS,GAAG,EAAE;AAC/C,SAAO,MAAM,UAAU,MAAM,OAAO;AACtC;AAgCO,SAAS,mBACd,SACU;AACV,QAAM,OAAO,oBAAoB,SAAS,GAAG,EAAE;AAC/C,SAAO,cAAc,MAAM,OAAO;AACpC;AAoCA,eAAsB,UACpB,UACA,SACkB;AAClB,QAAM,QAAQ,MAAM,gBAAgB;AAAA,IAClC,WAAW;AAAA,IACX,GAAG;AAAA,IACH,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,oBAAmB,sBAAM,GAAE,aAAa,QAAQ;AACtD,QAAM,UAAU,SAAS,OAAM,sBAAM,GAAE,aAAa,QAAQ,KAAK,CAAC,IAAI,OAAO;AAC7E,QAAM,mBAAe,2BAAc,iBAAAA,QAAK,SAAS,SAAS,gBAAgB,CAAC;AAC3E,SAAO,MAAM,SAAS,YAAY;AACpC;AAqCO,SAAS,cACd,UACA,SACS;AACT,QAAM,QAAQ,oBAAoB;AAAA,IAChC,WAAW;AAAA,IACX,GAAG;AAAA,IACH,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,oBAAmB,sBAAM,GAAE,aAAa,QAAQ;AACtD,QAAM,UAAU,SAAS,OAAM,sBAAM,GAAE,aAAa,QAAQ,KAAK,CAAC,IAAI,OAAO;AAC7E,QAAM,mBAAe,2BAAc,iBAAAA,QAAK,SAAS,SAAS,gBAAgB,CAAC;AAC3E,SAAO,MAAM,SAAS,YAAY;AACpC;AAoCA,eAAsB,WACpB,UACA,SACkB;AAClB,QAAM,QAAQ,MAAM,iBAAiB;AAAA,IACnC,WAAW;AAAA,IACX,GAAG;AAAA,IACH,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,oBAAmB,sBAAM,GAAE,aAAa,QAAQ;AACtD,QAAM,UAAU,SAAS,OAAM,sBAAM,GAAE,aAAa,QAAQ,KAAK,CAAC,IAAI,OAAO;AAC7E,QAAM,mBAAe,2BAAc,iBAAAA,QAAK,SAAS,SAAS,gBAAgB,CAAC;AAC3E,SAAO,MAAM,SAAS,YAAY;AACpC;AAqCO,SAAS,eACd,UACA,SACS;AACT,QAAM,QAAQ,qBAAqB;AAAA,IACjC,WAAW;AAAA,IACX,GAAG;AAAA,IACH,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,oBAAmB,sBAAM,GAAE,aAAa,QAAQ;AACtD,QAAM,UAAU,SAAS,OAAM,sBAAM,GAAE,aAAa,QAAQ,KAAK,CAAC,IAAI,OAAO;AAC7E,QAAM,mBAAe,2BAAc,iBAAAA,QAAK,SAAS,SAAS,gBAAgB,CAAC;AAC3E,SAAO,MAAM,SAAS,YAAY;AACpC;AAmCA,eAAsB,SACpB,UACA,SACkB;AAClB,QAAM,QAAQ,MAAM,eAAe;AAAA,IACjC,WAAW;AAAA,IACX,GAAG;AAAA,IACH,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,oBAAmB,sBAAM,GAAE,aAAa,QAAQ;AACtD,QAAM,UAAU,SAAS,OAAM,sBAAM,GAAE,aAAa,QAAQ,KAAK,CAAC,IAAI,OAAO;AAC7E,QAAM,mBAAe,2BAAc,iBAAAA,QAAK,SAAS,SAAS,gBAAgB,CAAC;AAC3E,SAAO,MAAM,SAAS,YAAY;AACpC;AAoCO,SAAS,aACd,UACA,SACS;AACT,QAAM,QAAQ,mBAAmB;AAAA,IAC/B,WAAW;AAAA,IACX,GAAG;AAAA,IACH,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,oBAAmB,sBAAM,GAAE,aAAa,QAAQ;AACtD,QAAM,UAAU,SAAS,OAAM,sBAAM,GAAE,aAAa,QAAQ,KAAK,CAAC,IAAI,OAAO;AAC7E,QAAM,mBAAe,2BAAc,iBAAAA,QAAK,SAAS,SAAS,gBAAgB,CAAC;AAC3E,SAAO,MAAM,SAAS,YAAY;AACpC;",
|
|
6
6
|
"names": ["result", "path", "relPath"]
|
|
7
7
|
}
|
package/dist/path.js
CHANGED
|
@@ -383,12 +383,20 @@ function relative(from, to) {
|
|
|
383
383
|
let lastCommonSep = -1;
|
|
384
384
|
let i = 0;
|
|
385
385
|
for (; i < length; i += 1) {
|
|
386
|
-
|
|
387
|
-
|
|
386
|
+
let fromCode = actualFrom.charCodeAt(fromStart + i);
|
|
387
|
+
let toCode = actualTo.charCodeAt(toStart + i);
|
|
388
|
+
if (WIN322) {
|
|
389
|
+
if (fromCode >= CHAR_UPPERCASE_A && fromCode <= CHAR_UPPERCASE_Z) {
|
|
390
|
+
fromCode += 32;
|
|
391
|
+
}
|
|
392
|
+
if (toCode >= CHAR_UPPERCASE_A && toCode <= CHAR_UPPERCASE_Z) {
|
|
393
|
+
toCode += 32;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
388
396
|
if (fromCode !== toCode) {
|
|
389
397
|
break;
|
|
390
398
|
}
|
|
391
|
-
if (/* @__PURE__ */ isPathSeparator(
|
|
399
|
+
if (/* @__PURE__ */ isPathSeparator(actualFrom.charCodeAt(fromStart + i))) {
|
|
392
400
|
lastCommonSep = i;
|
|
393
401
|
}
|
|
394
402
|
}
|
package/dist/path.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/path.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @fileoverview Path manipulation utilities with cross-platform support.\n * Provides path normalization, validation, and file extension handling.\n */\n\nimport { WIN32 } from '#constants/platform'\n\nimport { search } from './strings'\n\n// Character code constants.\n// '\\'\nconst CHAR_BACKWARD_SLASH = 92\n// ':'\nconst CHAR_COLON = 58\n// '/'\nconst CHAR_FORWARD_SLASH = 47\n// 'a'\nconst CHAR_LOWERCASE_A = 97\n// 'z'\nconst CHAR_LOWERCASE_Z = 122\n// 'A'\nconst CHAR_UPPERCASE_A = 65\n// 'Z'\nconst CHAR_UPPERCASE_Z = 90\n\n// Regular expressions.\nconst slashRegExp = /[/\\\\]/\nconst nodeModulesPathRegExp = /(?:^|[/\\\\])node_modules(?:[/\\\\]|$)/\n\n/**\n * Check if a character code represents a path separator.\n *\n * Determines whether the given character code is either a forward slash (/) or\n * backslash (\\), which are used as path separators across different platforms.\n *\n * @param {number} code - The character code to check\n * @returns {boolean} `true` if the code represents a path separator, `false` otherwise\n *\n * @example\n * ```typescript\n * isPathSeparator(47) // true - forward slash '/'\n * isPathSeparator(92) // true - backslash '\\'\n * isPathSeparator(65) // false - letter 'A'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction isPathSeparator(code: number): boolean {\n return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH\n}\n\n/**\n * Check if a character code represents a Windows device root letter.\n *\n * Tests whether the given character code falls within the valid range for\n * Windows drive letters (A-Z or a-z). These letters are used at the start\n * of Windows absolute paths (e.g., `C:\\`, `D:\\`).\n *\n * @param {number} code - The character code to check\n * @returns {boolean} `true` if the code is a valid drive letter, `false` otherwise\n *\n * @example\n * ```typescript\n * isWindowsDeviceRoot(67) // true - letter 'C'\n * isWindowsDeviceRoot(99) // true - letter 'c'\n * isWindowsDeviceRoot(58) // false - colon ':'\n * isWindowsDeviceRoot(47) // false - forward slash '/'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction isWindowsDeviceRoot(code: number): boolean {\n return (\n (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||\n (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z)\n )\n}\n\nlet _buffer: typeof import('node:buffer') | undefined\n/**\n * Lazily load the buffer module.\n *\n * Performs on-demand loading of Node.js buffer module to avoid initialization\n * overhead and potential Webpack bundling errors.\n *\n * @private\n * @returns {typeof import('node:buffer')} The buffer module\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getBuffer() {\n if (_buffer === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _buffer = /*@__PURE__*/ require('node:buffer')\n }\n return _buffer as typeof import('node:buffer')\n}\n\nlet _url: typeof import('node:url') | undefined\n/**\n * Lazily load the url module.\n *\n * Performs on-demand loading of Node.js url module to avoid initialization\n * overhead and potential Webpack bundling errors.\n *\n * @private\n * @returns {typeof import('node:url')} The url module\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getUrl() {\n if (_url === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _url = /*@__PURE__*/ require('node:url')\n }\n return _url as typeof import('node:url')\n}\n\n/**\n * Check if a path contains node_modules directory.\n *\n * Detects whether a given path includes a `node_modules` directory segment.\n * This is useful for identifying npm package dependencies and filtering\n * dependency-related paths.\n *\n * The check matches `node_modules` appearing as a complete path segment,\n * ensuring it is either at the start, end, or surrounded by path separators.\n *\n * @param {string | Buffer | URL} pathLike - The path to check\n * @returns {boolean} `true` if the path contains `node_modules`, `false` otherwise\n *\n * @example\n * ```typescript\n * isNodeModules('/project/node_modules/package') // true\n * isNodeModules('node_modules/package/index.js') // true\n * isNodeModules('/src/my_node_modules_backup') // false\n * isNodeModules('/project/src/index.js') // false\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isNodeModules(pathLike: string | Buffer | URL): boolean {\n const filepath = pathLikeToString(pathLike)\n return nodeModulesPathRegExp.test(filepath)\n}\n\n/**\n * Check if a path is absolute.\n *\n * An absolute path is one that specifies a location from the root of the file system.\n * This function handles both POSIX and Windows path formats.\n *\n * POSIX absolute paths:\n * - Start with forward slash '/'\n * - Examples: '/home/user', '/usr/bin/node'\n *\n * Windows absolute paths (3 types):\n * 1. Drive-letter paths: Start with drive letter + colon + separator\n * - Format: [A-Za-z]:[\\\\/]\n * - Examples: 'C:\\Windows', 'D:/data', 'c:\\Program Files'\n * - Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#file-and-directory-names\n *\n * 2. UNC paths: Start with double backslash (handled by backslash check)\n * - Format: \\\\server\\share\n * - Examples: '\\\\server\\share\\file', '\\\\?\\C:\\path'\n * - Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#unc-names\n *\n * 3. Device paths: Start with backslash\n * - Examples: '\\Windows', '\\\\.\\device'\n * - Note: Single backslash paths are relative to current drive\n *\n * @param {string | Buffer | URL} pathLike - The path to check\n * @returns {boolean} `true` if the path is absolute, `false` otherwise\n *\n * @example\n * ```typescript\n * // POSIX paths\n * isAbsolute('/home/user') // true\n * isAbsolute('/usr/bin/node') // true\n *\n * // Windows paths\n * isAbsolute('C:\\\\Windows') // true\n * isAbsolute('D:/data') // true\n * isAbsolute('\\\\\\\\server\\\\share') // true\n *\n * // Relative paths\n * isAbsolute('../relative') // false\n * isAbsolute('relative/path') // false\n * isAbsolute('.') // false\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isAbsolute(pathLike: string | Buffer | URL): boolean {\n const filepath = pathLikeToString(pathLike)\n const { length } = filepath\n\n // Empty paths are not absolute.\n if (length === 0) {\n return false\n }\n\n const code = filepath.charCodeAt(0)\n\n // POSIX: absolute paths start with forward slash '/'.\n // This is the simplest case and works for all UNIX-like systems.\n if (code === CHAR_FORWARD_SLASH) {\n return true\n }\n\n // Windows: absolute paths can start with backslash '\\'.\n // This includes UNC paths (\\\\server\\share) and device paths (\\\\.\\ or \\\\?\\).\n // Single backslash is technically relative to current drive, but treated as absolute.\n if (code === CHAR_BACKWARD_SLASH) {\n return true\n }\n\n // Windows: drive-letter absolute paths (e.g., C:\\, D:\\).\n // Format: [A-Za-z]:[\\\\/]\n // Requires at least 3 characters: drive letter + colon + separator.\n // Only treat as absolute on Windows platforms.\n if (WIN32 && length > 2) {\n // Check if first character is a letter (A-Z or a-z).\n // Check if second character is colon ':'.\n // Check if third character is a path separator (forward or backslash).\n // This matches patterns like 'C:\\', 'D:/', 'c:\\Users', etc.\n if (\n isWindowsDeviceRoot(code) &&\n filepath.charCodeAt(1) === CHAR_COLON &&\n isPathSeparator(filepath.charCodeAt(2))\n ) {\n return true\n }\n }\n\n // Not an absolute path.\n return false\n}\n\n/**\n * Check if a value is a valid file path (absolute or relative).\n *\n * Determines whether a given value represents a valid file system path.\n * This function distinguishes between file paths and other string formats\n * like package names, URLs, or bare module specifiers.\n *\n * Valid paths include:\n * - Absolute paths (e.g., `/usr/bin`, `C:\\Windows`)\n * - Relative paths with separators (e.g., `./src`, `../lib`)\n * - Special relative paths (`.`, `..`)\n * - Paths starting with `@` that have subpaths (e.g., `@scope/name/file`)\n *\n * Not considered paths:\n * - URLs with protocols (e.g., `http://`, `file://`, `git:`)\n * - Bare package names (e.g., `lodash`, `react`)\n * - Scoped package names without subpaths (e.g., `@scope/name`)\n *\n * @param {string | Buffer | URL} pathLike - The value to check\n * @returns {boolean} `true` if the value is a valid file path, `false` otherwise\n *\n * @example\n * ```typescript\n * // Valid paths\n * isPath('/absolute/path') // true\n * isPath('./relative/path') // true\n * isPath('../parent/dir') // true\n * isPath('.') // true\n * isPath('..') // true\n * isPath('@scope/name/subpath') // true\n * isPath('C:\\\\Windows') // true (Windows)\n *\n * // Not paths\n * isPath('lodash') // false - bare package name\n * isPath('@scope/package') // false - scoped package name\n * isPath('http://example.com') // false - URL\n * isPath('file://path') // false - file URL\n * isPath('') // false - empty string\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isPath(pathLike: string | Buffer | URL): boolean {\n const filepath = pathLikeToString(pathLike)\n if (typeof filepath !== 'string' || filepath.length === 0) {\n return false\n }\n\n // Exclude URLs with protocols (file:, http:, https:, git:, etc.).\n // These should be handled by package spec parsers, not treated as file paths.\n // Require at least 2 characters before colon to exclude Windows drive letters (C:, D:).\n if (/^[a-z][a-z0-9+.-]+:/i.test(filepath)) {\n return false\n }\n\n // Special relative paths.\n if (filepath === '.' || filepath === '..') {\n return true\n }\n\n // Absolute paths are always valid paths.\n if (isAbsolute(filepath)) {\n return true\n }\n\n // Contains path separators, so it's a path.\n if (filepath.includes('/') || filepath.includes('\\\\')) {\n // Distinguish scoped package names from paths starting with '@'.\n // Scoped packages: @scope/name (exactly 2 parts, no backslashes).\n // Paths: @scope/name/subpath (3+ parts) or @scope\\name (Windows backslash).\n // Special case: '@/' is a valid path (already handled by separator check).\n if (filepath.startsWith('@') && !filepath.startsWith('@/')) {\n const parts = filepath.split('/')\n // If exactly @scope/name with no Windows separators, it's a package name.\n if (parts.length <= 2 && !parts[1]?.includes('\\\\')) {\n return false\n }\n }\n return true\n }\n\n // Bare names without separators are package names, not paths.\n return false\n}\n\n/**\n * Check if a path is relative.\n *\n * Determines whether a given path is relative (i.e., not absolute). A path\n * is considered relative if it does not specify a location from the root of\n * the file system.\n *\n * Relative paths include:\n * - Paths starting with `.` or `..` (e.g., `./src`, `../lib`)\n * - Paths without leading separators (e.g., `src/file.js`)\n * - Empty strings (treated as relative)\n *\n * @param {string | Buffer | URL} pathLike - The path to check\n * @returns {boolean} `true` if the path is relative, `false` if absolute\n *\n * @example\n * ```typescript\n * // Relative paths\n * isRelative('./src/index.js') // true\n * isRelative('../lib/util.js') // true\n * isRelative('src/file.js') // true\n * isRelative('') // true\n *\n * // Absolute paths\n * isRelative('/home/user') // false\n * isRelative('C:\\\\Windows') // false (Windows)\n * isRelative('\\\\\\\\server\\\\share') // false (Windows UNC)\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isRelative(pathLike: string | Buffer | URL): boolean {\n const filepath = pathLikeToString(pathLike)\n if (typeof filepath !== 'string') {\n return false\n }\n // Empty string is considered relative.\n if (filepath.length === 0) {\n return true\n }\n // A path is relative if it's not absolute.\n return !isAbsolute(filepath)\n}\n\n/**\n * Normalize a path by converting backslashes to forward slashes and collapsing segments.\n *\n * This function performs several normalization operations:\n * - Converts all backslashes (`\\`) to forward slashes (`/`)\n * - Collapses repeated slashes into single slashes\n * - Resolves `.` (current directory) segments\n * - Resolves `..` (parent directory) segments\n * - Preserves UNC path prefixes (`//server/share`)\n * - Preserves Windows namespace prefixes (`//./`, `//?/`)\n * - Returns `.` for empty or collapsed paths\n *\n * Special handling:\n * - UNC paths: Maintains double leading slashes for `//server/share` format\n * - Windows namespaces: Preserves `//./` and `//?/` prefixes\n * - Leading `..` segments: Preserved in relative paths without prefix\n * - Trailing components: Properly handled when resolving `..`\n *\n * @param {string | Buffer | URL} pathLike - The path to normalize\n * @returns {string} The normalized path with forward slashes and collapsed segments\n *\n * @example\n * ```typescript\n * // Basic normalization\n * normalizePath('foo/bar//baz') // 'foo/bar/baz'\n * normalizePath('foo/./bar') // 'foo/bar'\n * normalizePath('foo/bar/../baz') // 'foo/baz'\n *\n * // Windows paths\n * normalizePath('C:\\\\Users\\\\John\\\\file.txt') // 'C:/Users/John/file.txt'\n * normalizePath('foo\\\\bar\\\\baz') // 'foo/bar/baz'\n *\n * // UNC paths\n * normalizePath('\\\\\\\\server\\\\share\\\\file') // '//server/share/file'\n *\n * // Edge cases\n * normalizePath('') // '.'\n * normalizePath('.') // '.'\n * normalizePath('..') // '..'\n * normalizePath('///foo///bar///') // '/foo/bar'\n * normalizePath('foo/../..') // '..'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function normalizePath(pathLike: string | Buffer | URL): string {\n const filepath = pathLikeToString(pathLike)\n const { length } = filepath\n if (length === 0) {\n return '.'\n }\n if (length < 2) {\n return length === 1 && filepath.charCodeAt(0) === 92 /*'\\\\'*/\n ? '/'\n : filepath\n }\n\n let code = 0\n let start = 0\n\n // Ensure win32 namespaces have two leading slashes so they are handled properly\n // by path.win32.parse() after being normalized.\n // https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#namespaces\n // UNC paths, paths starting with double slashes, e.g. \"\\\\\\\\wsl.localhost\\\\Ubuntu\\home\\\\\",\n // are okay to convert to forward slashes.\n // https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions\n let prefix = ''\n if (length > 4 && filepath.charCodeAt(3) === 92 /*'\\\\'*/) {\n const code2 = filepath.charCodeAt(2)\n // Look for \\\\?\\ or \\\\.\\\n if (\n (code2 === 63 /*'?'*/ || code2 === 46) /*'.'*/ &&\n filepath.charCodeAt(0) === 92 /*'\\\\'*/ &&\n filepath.charCodeAt(1) === 92 /*'\\\\'*/\n ) {\n start = 2\n prefix = '//'\n }\n }\n if (start === 0) {\n // Check for UNC paths first (\\\\server\\share or //server/share)\n // UNC paths must start with exactly two slashes, not more\n if (\n length > 2 &&\n ((filepath.charCodeAt(0) === 92 /*'\\\\'*/ &&\n filepath.charCodeAt(1) === 92 /*'\\\\'*/ &&\n filepath.charCodeAt(2) !== 92) /*'\\\\'*/ ||\n (filepath.charCodeAt(0) === 47 /*'/'*/ &&\n filepath.charCodeAt(1) === 47 /*'/'*/ &&\n filepath.charCodeAt(2) !== 47)) /*'/'*/\n ) {\n // Check if this is a valid UNC path: must have server/share format\n // Find the first segment (server name) and second segment (share name)\n let firstSegmentEnd = -1\n let hasSecondSegment = false\n\n // Skip leading slashes after the initial double slash\n let i = 2\n while (\n i < length &&\n (filepath.charCodeAt(i) === 47 /*'/'*/ ||\n filepath.charCodeAt(i) === 92) /*'\\\\'*/\n ) {\n i++\n }\n\n // Find the end of first segment (server name)\n while (i < length) {\n const char = filepath.charCodeAt(i)\n if (char === 47 /*'/'*/ || char === 92 /*'\\\\'*/) {\n firstSegmentEnd = i\n break\n }\n i++\n }\n\n if (firstSegmentEnd > 2) {\n // Skip slashes after server name\n i = firstSegmentEnd\n while (\n i < length &&\n (filepath.charCodeAt(i) === 47 /*'/'*/ ||\n filepath.charCodeAt(i) === 92) /*'\\\\'*/\n ) {\n i++\n }\n // Check if there's a share name (second segment)\n if (i < length) {\n hasSecondSegment = true\n }\n }\n\n if (firstSegmentEnd > 2 && hasSecondSegment) {\n // Valid UNC path - preserve double leading slashes\n start = 2\n prefix = '//'\n } else {\n // Just repeated slashes, treat as regular path\n code = filepath.charCodeAt(start)\n while (code === 47 /*'/'*/ || code === 92 /*'\\\\'*/) {\n start += 1\n code = filepath.charCodeAt(start)\n }\n if (start) {\n prefix = '/'\n }\n }\n } else {\n // Trim leading slashes for regular paths\n code = filepath.charCodeAt(start)\n while (code === 47 /*'/'*/ || code === 92 /*'\\\\'*/) {\n start += 1\n code = filepath.charCodeAt(start)\n }\n if (start) {\n prefix = '/'\n }\n }\n }\n let nextIndex = search(filepath, slashRegExp, { fromIndex: start })\n if (nextIndex === -1) {\n const segment = filepath.slice(start)\n if (segment === '.' || segment.length === 0) {\n return prefix || '.'\n }\n if (segment === '..') {\n return prefix ? prefix.slice(0, -1) || '/' : '..'\n }\n return prefix + segment\n }\n // Process segments and handle '.', '..', and empty segments.\n let collapsed = ''\n let segmentCount = 0\n let leadingDotDots = 0\n while (nextIndex !== -1) {\n const segment = filepath.slice(start, nextIndex)\n if (segment.length > 0 && segment !== '.') {\n if (segment === '..') {\n // Handle '..' by removing the last segment if possible.\n if (segmentCount > 0) {\n // Find the last separator and remove the last segment.\n const lastSeparatorIndex = collapsed.lastIndexOf('/')\n if (lastSeparatorIndex === -1) {\n // Only one segment, remove it entirely.\n collapsed = ''\n segmentCount = 0\n // Check if this was a leading '..', restore it.\n if (leadingDotDots > 0 && !prefix) {\n collapsed = '..'\n leadingDotDots = 1\n }\n } else {\n const lastSegmentStart = lastSeparatorIndex + 1\n const lastSegmentValue = collapsed.slice(lastSegmentStart)\n // Don't collapse leading '..' segments.\n if (lastSegmentValue === '..') {\n // Preserve the '..' and add another one.\n collapsed = `${collapsed}/${segment}`\n leadingDotDots += 1\n } else {\n // Normal collapse: remove the last segment.\n collapsed = collapsed.slice(0, lastSeparatorIndex)\n segmentCount -= 1\n }\n }\n } else if (!prefix) {\n // Preserve '..' for relative paths.\n collapsed = collapsed + (collapsed.length === 0 ? '' : '/') + segment\n leadingDotDots += 1\n }\n } else {\n collapsed = collapsed + (collapsed.length === 0 ? '' : '/') + segment\n segmentCount += 1\n }\n }\n start = nextIndex + 1\n code = filepath.charCodeAt(start)\n while (code === 47 /*'/'*/ || code === 92 /*'\\\\'*/) {\n start += 1\n code = filepath.charCodeAt(start)\n }\n nextIndex = search(filepath, slashRegExp, { fromIndex: start })\n }\n const lastSegment = filepath.slice(start)\n if (lastSegment.length > 0 && lastSegment !== '.') {\n if (lastSegment === '..') {\n if (segmentCount > 0) {\n const lastSeparatorIndex = collapsed.lastIndexOf('/')\n if (lastSeparatorIndex === -1) {\n collapsed = ''\n segmentCount = 0\n // Check if this was a leading '..', restore it.\n if (leadingDotDots > 0 && !prefix) {\n collapsed = '..'\n leadingDotDots = 1\n }\n } else {\n const lastSegmentStart = lastSeparatorIndex + 1\n const lastSegmentValue = collapsed.slice(lastSegmentStart)\n // Don't collapse leading '..' segments.\n if (lastSegmentValue === '..') {\n // Preserve the '..' and add another one.\n collapsed = `${collapsed}/${lastSegment}`\n leadingDotDots += 1\n } else {\n // Normal collapse: remove the last segment.\n collapsed = collapsed.slice(0, lastSeparatorIndex)\n segmentCount -= 1\n }\n }\n } else if (!prefix) {\n collapsed =\n collapsed + (collapsed.length === 0 ? '' : '/') + lastSegment\n leadingDotDots += 1\n }\n } else {\n collapsed = collapsed + (collapsed.length === 0 ? '' : '/') + lastSegment\n segmentCount += 1\n }\n }\n\n if (collapsed.length === 0) {\n return prefix || '.'\n }\n return prefix + collapsed\n}\n\n/**\n * Convert a path-like value to a string.\n *\n * Converts various path-like types (string, Buffer, URL) into a normalized\n * string representation. This function handles different input formats and\n * provides consistent string output for path operations.\n *\n * Supported input types:\n * - `string`: Returned as-is\n * - `Buffer`: Decoded as UTF-8 string\n * - `URL`: Converted using `fileURLToPath()`, with fallback for malformed URLs\n * - `null` / `undefined`: Returns empty string\n *\n * URL handling:\n * - Valid file URLs are converted via `url.fileURLToPath()`\n * - Malformed URLs fall back to pathname extraction with decoding\n * - Windows drive letters in URLs are handled specially\n * - Percent-encoded characters are decoded (e.g., `%20` becomes space)\n *\n * @param {string | Buffer | URL | null | undefined} pathLike - The path-like value to convert\n * @returns {string} The string representation of the path, or empty string for null/undefined\n *\n * @example\n * ```typescript\n * // String input\n * pathLikeToString('/home/user') // '/home/user'\n *\n * // Buffer input\n * pathLikeToString(Buffer.from('/tmp/file')) // '/tmp/file'\n *\n * // URL input\n * pathLikeToString(new URL('file:///home/user')) // '/home/user'\n * pathLikeToString(new URL('file:///C:/Windows')) // 'C:/Windows' (Windows)\n *\n * // Null/undefined input\n * pathLikeToString(null) // ''\n * pathLikeToString(undefined) // ''\n *\n * // Percent-encoded URLs\n * pathLikeToString(new URL('file:///path%20with%20spaces')) // '/path with spaces'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function pathLikeToString(\n pathLike: string | Buffer | URL | null | undefined,\n): string {\n if (pathLike === null || pathLike === undefined) {\n return ''\n }\n if (typeof pathLike === 'string') {\n return pathLike\n }\n const { Buffer } = getBuffer()\n if (Buffer.isBuffer(pathLike)) {\n return pathLike.toString('utf8')\n }\n const url = getUrl()\n if (pathLike instanceof URL) {\n try {\n return url.fileURLToPath(pathLike)\n } catch {\n // On Windows, file URLs like `file:///C:/path` include drive letters.\n // If a file URL is missing its drive letter (malformed), fileURLToPath() throws an error.\n // This fallback extracts the pathname directly from the URL object.\n //\n // Example flows:\n // - Unix: file:///home/user \u2192 pathname '/home/user' \u2192 keep as-is\n // - Windows valid: file:///C:/path \u2192 handled by fileURLToPath()\n // - Windows invalid: file:///path \u2192 pathname '/path' \u2192 strips to 'path'\n const pathname = pathLike.pathname\n\n // Decode percent-encoded characters (e.g., %20 \u2192 space).\n // The pathname property keeps URL encoding, but file paths need decoded characters.\n // This is not platform-specific; all URLs use percent-encoding regardless of OS.\n const decodedPathname = decodeURIComponent(pathname)\n\n // URL pathnames always start with `/`.\n // On Windows, strip the leading slash only for malformed URLs that lack drive letters\n // (e.g., `/path` should be `path`, but `/C:/path` should be `C:/path`).\n // On Unix, keep the leading slash for absolute paths (e.g., `/home/user`).\n const WIN32 = require('../constants/platform').WIN32\n if (WIN32 && decodedPathname.startsWith('/')) {\n // Check for drive letter pattern following Node.js source: /[a-zA-Z]:/\n // Character at index 1 should be a letter, character at index 2 should be ':'\n // Convert to lowercase\n const letter = decodedPathname.charCodeAt(1) | 0x20\n const hasValidDriveLetter =\n decodedPathname.length >= 3 &&\n letter >= 97 &&\n // 'a' to 'z'\n letter <= 122 &&\n decodedPathname.charAt(2) === ':'\n\n if (!hasValidDriveLetter) {\n // On Windows, preserve Unix-style absolute paths that don't start with a drive letter.\n // Only strip the leading slash for truly malformed Windows paths.\n // Since fileURLToPath() failed, this is likely a valid Unix-style absolute path.\n return decodedPathname\n }\n }\n return decodedPathname\n }\n }\n return String(pathLike)\n}\n\n/**\n * Split a path into an array of segments.\n *\n * Divides a path into individual components by splitting on path separators\n * (both forward slashes and backslashes). This is useful for path traversal,\n * analysis, and manipulation.\n *\n * The function handles:\n * - Forward slashes (`/`) on all platforms\n * - Backslashes (`\\`) on Windows\n * - Mixed separators in a single path\n * - Empty paths (returns empty array)\n *\n * Note: The resulting array may contain empty strings if the path has leading,\n * trailing, or consecutive separators (e.g., `/foo//bar/` becomes `['', 'foo', '', 'bar', '']`).\n *\n * @param {string | Buffer | URL} pathLike - The path to split\n * @returns {string[]} Array of path segments, or empty array for empty paths\n *\n * @example\n * ```typescript\n * // POSIX paths\n * splitPath('/home/user/file.txt') // ['', 'home', 'user', 'file.txt']\n * splitPath('src/lib/util.js') // ['src', 'lib', 'util.js']\n *\n * // Windows paths\n * splitPath('C:\\\\Users\\\\John') // ['C:', 'Users', 'John']\n * splitPath('folder\\\\file.txt') // ['folder', 'file.txt']\n *\n * // Mixed separators\n * splitPath('path/to\\\\file') // ['path', 'to', 'file']\n *\n * // Edge cases\n * splitPath('') // []\n * splitPath('/') // ['', '']\n * splitPath('/foo//bar/') // ['', 'foo', '', 'bar', '']\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function splitPath(pathLike: string | Buffer | URL): string[] {\n const filepath = pathLikeToString(pathLike)\n if (filepath === '') {\n return []\n }\n return filepath.split(slashRegExp)\n}\n\n/**\n * Remove leading ./ or ../ from a path.\n *\n * Strips the `./` or `.\\` prefix from relative paths. This is useful for\n * normalizing paths when the current directory reference is implicit or\n * unwanted.\n *\n * Note: This function only removes a single leading `./` or `.\\`. It does\n * not remove `../` prefixes or process the rest of the path.\n *\n * @param {string | Buffer | URL} pathLike - The path to process\n * @returns {string} The path without leading `./` or `.\\`, or unchanged if no such prefix\n *\n * @example\n * ```typescript\n * // Remove ./ prefix\n * trimLeadingDotSlash('./src/index.js') // 'src/index.js'\n * trimLeadingDotSlash('.\\\\src\\\\file.txt') // 'src\\\\file.txt'\n *\n * // Preserve ../ prefix\n * trimLeadingDotSlash('../lib/util.js') // '../lib/util.js'\n *\n * // No change for other paths\n * trimLeadingDotSlash('/absolute/path') // '/absolute/path'\n * trimLeadingDotSlash('relative/path') // 'relative/path'\n * trimLeadingDotSlash('.') // '.'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function trimLeadingDotSlash(pathLike: string | Buffer | URL): string {\n const filepath = pathLikeToString(pathLike)\n // Only trim ./ not ../\n if (filepath.startsWith('./') || filepath.startsWith('.\\\\')) {\n return filepath.slice(2)\n }\n return filepath\n}\n\n/**\n * Resolve an absolute path from path segments.\n *\n * This function mimics Node.js `path.resolve()` behavior by building an\n * absolute path from the given segments. It processes segments from right\n * to left, stopping when an absolute path is encountered. If no absolute\n * path is found, it prepends the current working directory.\n *\n * Algorithm:\n * 1. Process segments from right to left\n * 2. Stop when an absolute path is found\n * 3. Prepend current working directory if no absolute path found\n * 4. Normalize the final path\n *\n * Key behaviors:\n * - Later segments override earlier ones (e.g., `resolve('/foo', '/bar')` returns `/bar`)\n * - Empty or non-string segments are skipped\n * - Result is always an absolute path\n * - Path separators are normalized to forward slashes\n *\n * @param {...string} segments - Path segments to resolve\n * @returns {string} The resolved absolute path\n *\n * @example\n * ```typescript\n * // Basic resolution\n * resolve('foo', 'bar', 'baz') // '/cwd/foo/bar/baz' (assuming cwd is '/cwd')\n * resolve('/foo', 'bar', 'baz') // '/foo/bar/baz'\n * resolve('foo', '/bar', 'baz') // '/bar/baz'\n *\n * // Windows paths\n * resolve('C:\\\\foo', 'bar') // 'C:/foo/bar'\n *\n * // Empty segments\n * resolve('foo', '', 'bar') // '/cwd/foo/bar'\n * resolve() // '/cwd' (current directory)\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction resolve(...segments: string[]): string {\n let resolvedPath = ''\n let resolvedAbsolute = false\n\n // Process segments from right to left until we find an absolute path.\n // This allows later segments to override earlier ones.\n // Example: resolve('/foo', '/bar') returns '/bar', not '/foo/bar'.\n for (let i = segments.length - 1; i >= 0 && !resolvedAbsolute; i -= 1) {\n const segment = segments[i]\n\n // Skip empty or non-string segments.\n if (typeof segment !== 'string' || segment.length === 0) {\n continue\n }\n\n // Prepend the segment to the resolved path.\n // Use forward slashes as separators (normalized later).\n resolvedPath =\n segment + (resolvedPath.length === 0 ? '' : `/${resolvedPath}`)\n\n // Check if this segment is absolute.\n // Absolute paths stop the resolution process.\n resolvedAbsolute = isAbsolute(segment)\n }\n\n // If no absolute path was found in segments, prepend current working directory.\n // This ensures the final path is always absolute.\n if (!resolvedAbsolute) {\n const cwd = /*@__PURE__*/ require('node:process').cwd()\n resolvedPath = cwd + (resolvedPath.length === 0 ? '' : `/${resolvedPath}`)\n }\n\n // Normalize the resolved path (collapse '..' and '.', convert separators).\n return normalizePath(resolvedPath)\n}\n\n/**\n * Calculate the relative path from one path to another.\n *\n * This function computes how to get from the `from` path to the `to` path\n * using relative path notation. Both paths are first resolved to absolute\n * paths, then compared to find the common base path, and finally a relative\n * path is constructed using `../` for parent directory traversal.\n *\n * Algorithm:\n * 1. Resolve both paths to absolute\n * 2. Find the longest common path prefix (up to a separator)\n * 3. For each remaining directory in `from`, add `../` to go up\n * 4. Append the remaining path from `to`\n *\n * Windows-specific behavior:\n * - File system paths are case-insensitive on Windows (NTFS, FAT32)\n * - `C:\\Foo` and `c:\\foo` are considered the same path\n * - Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file\n * - Case is preserved but not significant for comparison\n *\n * @param {string} from - The source path (starting point)\n * @param {string} to - The destination path (target)\n * @returns {string} The relative path from `from` to `to`, or empty string if paths are identical\n *\n * @example\n * ```typescript\n * // Basic relative paths\n * relative('/foo/bar', '/foo/baz') // '../baz'\n * relative('/foo/bar/baz', '/foo') // '../..'\n * relative('/foo', '/foo/bar') // 'bar'\n *\n * // Same paths\n * relative('/foo/bar', '/foo/bar') // ''\n *\n * // Windows case-insensitive\n * relative('C:\\\\Foo\\\\bar', 'C:\\\\foo\\\\baz') // '../baz' (Windows)\n *\n * // Root paths\n * relative('/', '/foo/bar') // 'foo/bar'\n * relative('/foo/bar', '/') // '../..'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction relative(from: string, to: string): string {\n // Quick return if paths are already identical.\n if (from === to) {\n return ''\n }\n\n // Resolve both paths to absolute.\n // This handles relative paths, '.', '..', and ensures consistent format.\n const actualFrom = resolve(from)\n const actualTo = resolve(to)\n\n // Check again after resolution (paths might have been equivalent).\n if (actualFrom === actualTo) {\n return ''\n }\n\n const WIN32 = require('../constants/platform').WIN32\n\n // Windows: perform case-insensitive comparison.\n // NTFS and FAT32 preserve case but are case-insensitive for lookups.\n // This means 'C:\\Foo\\bar.txt' and 'c:\\foo\\BAR.TXT' refer to the same file.\n // Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#case-sensitivity\n if (WIN32) {\n const fromLower = actualFrom.toLowerCase()\n const toLower = actualTo.toLowerCase()\n if (fromLower === toLower) {\n return ''\n }\n }\n\n // Skip the leading separator for comparison.\n // We compare paths starting after the root separator to find common directories.\n // Example: '/foo/bar' becomes 'foo/bar' for comparison (index 1).\n const fromStart = 1\n const fromEnd = actualFrom.length\n const fromLen = fromEnd - fromStart\n const toStart = 1\n const toEnd = actualTo.length\n const toLen = toEnd - toStart\n\n // Compare paths character by character to find the longest common prefix.\n // We only consider a common prefix valid if it ends at a directory separator.\n const length = fromLen < toLen ? fromLen : toLen\n // Index of last common directory separator.\n let lastCommonSep = -1\n let i = 0\n\n for (; i < length; i += 1) {\n const fromCode = actualFrom.charCodeAt(fromStart + i)\n const toCode = actualTo.charCodeAt(toStart + i)\n\n // Paths diverge at this character.\n if (fromCode !== toCode) {\n break\n }\n\n // Track directory separators (both forward and backslash for Windows compatibility).\n // We need this to ensure we only split at directory boundaries.\n if (isPathSeparator(fromCode)) {\n lastCommonSep = i\n }\n }\n\n // Handle edge cases where one path is a prefix of the other.\n if (i === length) {\n if (toLen > length) {\n // Destination path is longer.\n const toCode = actualTo.charCodeAt(toStart + i)\n if (isPathSeparator(toCode)) {\n // `from` is the exact base path for `to`.\n // Example: from='/foo/bar'; to='/foo/bar/baz' \u2192 'baz'\n // Skip the separator character (+1) to get just the relative portion.\n return actualTo.slice(toStart + i + 1)\n }\n if (i === 0) {\n // `from` is the root directory.\n // Example: from='/'; to='/foo' \u2192 'foo'\n return actualTo.slice(toStart + i)\n }\n } else if (fromLen > length) {\n // Source path is longer.\n const fromCode = actualFrom.charCodeAt(fromStart + i)\n if (isPathSeparator(fromCode)) {\n // `to` is the exact base path for `from`.\n // Example: from='/foo/bar/baz'; to='/foo/bar' \u2192 '..'\n // We need to go up from the extra directory.\n lastCommonSep = i\n } else if (i === 0) {\n // `to` is the root directory.\n // Example: from='/foo'; to='/' \u2192 '..'\n lastCommonSep = 0\n }\n }\n }\n\n // Generate the relative path by constructing '../' segments.\n let out = ''\n\n // Count the number of directories in `from` after the common base.\n // For each directory, we need to go up one level ('../').\n // Example: from='/a/b/c', to='/a/x' \u2192 common='a', need '../..' (up from c, up from b)\n for (i = fromStart + lastCommonSep + 1; i <= fromEnd; i += 1) {\n const code = actualFrom.charCodeAt(i)\n\n // At the end of the path or at a separator, add '../'.\n if (i === fromEnd || isPathSeparator(code)) {\n out += out.length === 0 ? '..' : '/..'\n }\n }\n\n // Append the rest of the destination path after the common base.\n // This gives us the path from the common ancestor to the destination.\n return out + actualTo.slice(toStart + lastCommonSep)\n}\n\n/**\n * Get the relative path from one path to another.\n *\n * Computes the relative path from `from` to `to` and normalizes the result.\n * This is a convenience wrapper around the `relative()` function that adds\n * path normalization (converting separators and collapsing segments).\n *\n * The function:\n * 1. Calculates the relative path using `relative()`\n * 2. Normalizes the result using `normalizePath()`\n * 3. Preserves empty strings (same path) without converting to `.`\n *\n * @param {string} from - The source path (starting point)\n * @param {string} to - The destination path (target)\n * @returns {string} The normalized relative path from `from` to `to`, or empty string if paths are identical\n *\n * @example\n * ```typescript\n * // Basic usage\n * relativeResolve('/foo/bar', '/foo/baz') // '../baz'\n * relativeResolve('/foo/bar/baz', '/foo') // '../..'\n * relativeResolve('/foo', '/foo/bar') // 'bar'\n *\n * // Same paths\n * relativeResolve('/foo/bar', '/foo/bar') // ''\n *\n * // Windows paths (normalized)\n * relativeResolve('C:\\\\foo\\\\bar', 'C:\\\\foo\\\\baz') // '../baz'\n *\n * // With normalization\n * relativeResolve('/foo/./bar', '/foo/baz') // '../baz'\n * relativeResolve('/foo/bar/../baz', '/foo/qux') // '../qux'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function relativeResolve(from: string, to: string): string {\n const rel = relative(from, to)\n // Empty string means same path - don't normalize to '.'\n if (rel === '') {\n return ''\n }\n return normalizePath(rel)\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview Path manipulation utilities with cross-platform support.\n * Provides path normalization, validation, and file extension handling.\n */\n\nimport { WIN32 } from '#constants/platform'\n\nimport { search } from './strings'\n\n// Character code constants.\n// '\\'\nconst CHAR_BACKWARD_SLASH = 92\n// ':'\nconst CHAR_COLON = 58\n// '/'\nconst CHAR_FORWARD_SLASH = 47\n// 'a'\nconst CHAR_LOWERCASE_A = 97\n// 'z'\nconst CHAR_LOWERCASE_Z = 122\n// 'A'\nconst CHAR_UPPERCASE_A = 65\n// 'Z'\nconst CHAR_UPPERCASE_Z = 90\n\n// Regular expressions.\nconst slashRegExp = /[/\\\\]/\nconst nodeModulesPathRegExp = /(?:^|[/\\\\])node_modules(?:[/\\\\]|$)/\n\n/**\n * Check if a character code represents a path separator.\n *\n * Determines whether the given character code is either a forward slash (/) or\n * backslash (\\), which are used as path separators across different platforms.\n *\n * @param {number} code - The character code to check\n * @returns {boolean} `true` if the code represents a path separator, `false` otherwise\n *\n * @example\n * ```typescript\n * isPathSeparator(47) // true - forward slash '/'\n * isPathSeparator(92) // true - backslash '\\'\n * isPathSeparator(65) // false - letter 'A'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction isPathSeparator(code: number): boolean {\n return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH\n}\n\n/**\n * Check if a character code represents a Windows device root letter.\n *\n * Tests whether the given character code falls within the valid range for\n * Windows drive letters (A-Z or a-z). These letters are used at the start\n * of Windows absolute paths (e.g., `C:\\`, `D:\\`).\n *\n * @param {number} code - The character code to check\n * @returns {boolean} `true` if the code is a valid drive letter, `false` otherwise\n *\n * @example\n * ```typescript\n * isWindowsDeviceRoot(67) // true - letter 'C'\n * isWindowsDeviceRoot(99) // true - letter 'c'\n * isWindowsDeviceRoot(58) // false - colon ':'\n * isWindowsDeviceRoot(47) // false - forward slash '/'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction isWindowsDeviceRoot(code: number): boolean {\n return (\n (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||\n (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z)\n )\n}\n\nlet _buffer: typeof import('node:buffer') | undefined\n/**\n * Lazily load the buffer module.\n *\n * Performs on-demand loading of Node.js buffer module to avoid initialization\n * overhead and potential Webpack bundling errors.\n *\n * @private\n * @returns {typeof import('node:buffer')} The buffer module\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getBuffer() {\n if (_buffer === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _buffer = /*@__PURE__*/ require('node:buffer')\n }\n return _buffer as typeof import('node:buffer')\n}\n\nlet _url: typeof import('node:url') | undefined\n/**\n * Lazily load the url module.\n *\n * Performs on-demand loading of Node.js url module to avoid initialization\n * overhead and potential Webpack bundling errors.\n *\n * @private\n * @returns {typeof import('node:url')} The url module\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getUrl() {\n if (_url === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _url = /*@__PURE__*/ require('node:url')\n }\n return _url as typeof import('node:url')\n}\n\n/**\n * Check if a path contains node_modules directory.\n *\n * Detects whether a given path includes a `node_modules` directory segment.\n * This is useful for identifying npm package dependencies and filtering\n * dependency-related paths.\n *\n * The check matches `node_modules` appearing as a complete path segment,\n * ensuring it is either at the start, end, or surrounded by path separators.\n *\n * @param {string | Buffer | URL} pathLike - The path to check\n * @returns {boolean} `true` if the path contains `node_modules`, `false` otherwise\n *\n * @example\n * ```typescript\n * isNodeModules('/project/node_modules/package') // true\n * isNodeModules('node_modules/package/index.js') // true\n * isNodeModules('/src/my_node_modules_backup') // false\n * isNodeModules('/project/src/index.js') // false\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isNodeModules(pathLike: string | Buffer | URL): boolean {\n const filepath = pathLikeToString(pathLike)\n return nodeModulesPathRegExp.test(filepath)\n}\n\n/**\n * Check if a path is absolute.\n *\n * An absolute path is one that specifies a location from the root of the file system.\n * This function handles both POSIX and Windows path formats.\n *\n * POSIX absolute paths:\n * - Start with forward slash '/'\n * - Examples: '/home/user', '/usr/bin/node'\n *\n * Windows absolute paths (3 types):\n * 1. Drive-letter paths: Start with drive letter + colon + separator\n * - Format: [A-Za-z]:[\\\\/]\n * - Examples: 'C:\\Windows', 'D:/data', 'c:\\Program Files'\n * - Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#file-and-directory-names\n *\n * 2. UNC paths: Start with double backslash (handled by backslash check)\n * - Format: \\\\server\\share\n * - Examples: '\\\\server\\share\\file', '\\\\?\\C:\\path'\n * - Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#unc-names\n *\n * 3. Device paths: Start with backslash\n * - Examples: '\\Windows', '\\\\.\\device'\n * - Note: Single backslash paths are relative to current drive\n *\n * @param {string | Buffer | URL} pathLike - The path to check\n * @returns {boolean} `true` if the path is absolute, `false` otherwise\n *\n * @example\n * ```typescript\n * // POSIX paths\n * isAbsolute('/home/user') // true\n * isAbsolute('/usr/bin/node') // true\n *\n * // Windows paths\n * isAbsolute('C:\\\\Windows') // true\n * isAbsolute('D:/data') // true\n * isAbsolute('\\\\\\\\server\\\\share') // true\n *\n * // Relative paths\n * isAbsolute('../relative') // false\n * isAbsolute('relative/path') // false\n * isAbsolute('.') // false\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isAbsolute(pathLike: string | Buffer | URL): boolean {\n const filepath = pathLikeToString(pathLike)\n const { length } = filepath\n\n // Empty paths are not absolute.\n if (length === 0) {\n return false\n }\n\n const code = filepath.charCodeAt(0)\n\n // POSIX: absolute paths start with forward slash '/'.\n // This is the simplest case and works for all UNIX-like systems.\n if (code === CHAR_FORWARD_SLASH) {\n return true\n }\n\n // Windows: absolute paths can start with backslash '\\'.\n // This includes UNC paths (\\\\server\\share) and device paths (\\\\.\\ or \\\\?\\).\n // Single backslash is technically relative to current drive, but treated as absolute.\n if (code === CHAR_BACKWARD_SLASH) {\n return true\n }\n\n // Windows: drive-letter absolute paths (e.g., C:\\, D:\\).\n // Format: [A-Za-z]:[\\\\/]\n // Requires at least 3 characters: drive letter + colon + separator.\n // Only treat as absolute on Windows platforms.\n if (WIN32 && length > 2) {\n // Check if first character is a letter (A-Z or a-z).\n // Check if second character is colon ':'.\n // Check if third character is a path separator (forward or backslash).\n // This matches patterns like 'C:\\', 'D:/', 'c:\\Users', etc.\n if (\n isWindowsDeviceRoot(code) &&\n filepath.charCodeAt(1) === CHAR_COLON &&\n isPathSeparator(filepath.charCodeAt(2))\n ) {\n return true\n }\n }\n\n // Not an absolute path.\n return false\n}\n\n/**\n * Check if a value is a valid file path (absolute or relative).\n *\n * Determines whether a given value represents a valid file system path.\n * This function distinguishes between file paths and other string formats\n * like package names, URLs, or bare module specifiers.\n *\n * Valid paths include:\n * - Absolute paths (e.g., `/usr/bin`, `C:\\Windows`)\n * - Relative paths with separators (e.g., `./src`, `../lib`)\n * - Special relative paths (`.`, `..`)\n * - Paths starting with `@` that have subpaths (e.g., `@scope/name/file`)\n *\n * Not considered paths:\n * - URLs with protocols (e.g., `http://`, `file://`, `git:`)\n * - Bare package names (e.g., `lodash`, `react`)\n * - Scoped package names without subpaths (e.g., `@scope/name`)\n *\n * @param {string | Buffer | URL} pathLike - The value to check\n * @returns {boolean} `true` if the value is a valid file path, `false` otherwise\n *\n * @example\n * ```typescript\n * // Valid paths\n * isPath('/absolute/path') // true\n * isPath('./relative/path') // true\n * isPath('../parent/dir') // true\n * isPath('.') // true\n * isPath('..') // true\n * isPath('@scope/name/subpath') // true\n * isPath('C:\\\\Windows') // true (Windows)\n *\n * // Not paths\n * isPath('lodash') // false - bare package name\n * isPath('@scope/package') // false - scoped package name\n * isPath('http://example.com') // false - URL\n * isPath('file://path') // false - file URL\n * isPath('') // false - empty string\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isPath(pathLike: string | Buffer | URL): boolean {\n const filepath = pathLikeToString(pathLike)\n if (typeof filepath !== 'string' || filepath.length === 0) {\n return false\n }\n\n // Exclude URLs with protocols (file:, http:, https:, git:, etc.).\n // These should be handled by package spec parsers, not treated as file paths.\n // Require at least 2 characters before colon to exclude Windows drive letters (C:, D:).\n if (/^[a-z][a-z0-9+.-]+:/i.test(filepath)) {\n return false\n }\n\n // Special relative paths.\n if (filepath === '.' || filepath === '..') {\n return true\n }\n\n // Absolute paths are always valid paths.\n if (isAbsolute(filepath)) {\n return true\n }\n\n // Contains path separators, so it's a path.\n if (filepath.includes('/') || filepath.includes('\\\\')) {\n // Distinguish scoped package names from paths starting with '@'.\n // Scoped packages: @scope/name (exactly 2 parts, no backslashes).\n // Paths: @scope/name/subpath (3+ parts) or @scope\\name (Windows backslash).\n // Special case: '@/' is a valid path (already handled by separator check).\n if (filepath.startsWith('@') && !filepath.startsWith('@/')) {\n const parts = filepath.split('/')\n // If exactly @scope/name with no Windows separators, it's a package name.\n if (parts.length <= 2 && !parts[1]?.includes('\\\\')) {\n return false\n }\n }\n return true\n }\n\n // Bare names without separators are package names, not paths.\n return false\n}\n\n/**\n * Check if a path is relative.\n *\n * Determines whether a given path is relative (i.e., not absolute). A path\n * is considered relative if it does not specify a location from the root of\n * the file system.\n *\n * Relative paths include:\n * - Paths starting with `.` or `..` (e.g., `./src`, `../lib`)\n * - Paths without leading separators (e.g., `src/file.js`)\n * - Empty strings (treated as relative)\n *\n * @param {string | Buffer | URL} pathLike - The path to check\n * @returns {boolean} `true` if the path is relative, `false` if absolute\n *\n * @example\n * ```typescript\n * // Relative paths\n * isRelative('./src/index.js') // true\n * isRelative('../lib/util.js') // true\n * isRelative('src/file.js') // true\n * isRelative('') // true\n *\n * // Absolute paths\n * isRelative('/home/user') // false\n * isRelative('C:\\\\Windows') // false (Windows)\n * isRelative('\\\\\\\\server\\\\share') // false (Windows UNC)\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isRelative(pathLike: string | Buffer | URL): boolean {\n const filepath = pathLikeToString(pathLike)\n if (typeof filepath !== 'string') {\n return false\n }\n // Empty string is considered relative.\n if (filepath.length === 0) {\n return true\n }\n // A path is relative if it's not absolute.\n return !isAbsolute(filepath)\n}\n\n/**\n * Normalize a path by converting backslashes to forward slashes and collapsing segments.\n *\n * This function performs several normalization operations:\n * - Converts all backslashes (`\\`) to forward slashes (`/`)\n * - Collapses repeated slashes into single slashes\n * - Resolves `.` (current directory) segments\n * - Resolves `..` (parent directory) segments\n * - Preserves UNC path prefixes (`//server/share`)\n * - Preserves Windows namespace prefixes (`//./`, `//?/`)\n * - Returns `.` for empty or collapsed paths\n *\n * Special handling:\n * - UNC paths: Maintains double leading slashes for `//server/share` format\n * - Windows namespaces: Preserves `//./` and `//?/` prefixes\n * - Leading `..` segments: Preserved in relative paths without prefix\n * - Trailing components: Properly handled when resolving `..`\n *\n * @param {string | Buffer | URL} pathLike - The path to normalize\n * @returns {string} The normalized path with forward slashes and collapsed segments\n *\n * @example\n * ```typescript\n * // Basic normalization\n * normalizePath('foo/bar//baz') // 'foo/bar/baz'\n * normalizePath('foo/./bar') // 'foo/bar'\n * normalizePath('foo/bar/../baz') // 'foo/baz'\n *\n * // Windows paths\n * normalizePath('C:\\\\Users\\\\John\\\\file.txt') // 'C:/Users/John/file.txt'\n * normalizePath('foo\\\\bar\\\\baz') // 'foo/bar/baz'\n *\n * // UNC paths\n * normalizePath('\\\\\\\\server\\\\share\\\\file') // '//server/share/file'\n *\n * // Edge cases\n * normalizePath('') // '.'\n * normalizePath('.') // '.'\n * normalizePath('..') // '..'\n * normalizePath('///foo///bar///') // '/foo/bar'\n * normalizePath('foo/../..') // '..'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function normalizePath(pathLike: string | Buffer | URL): string {\n const filepath = pathLikeToString(pathLike)\n const { length } = filepath\n if (length === 0) {\n return '.'\n }\n if (length < 2) {\n return length === 1 && filepath.charCodeAt(0) === 92 /*'\\\\'*/\n ? '/'\n : filepath\n }\n\n let code = 0\n let start = 0\n\n // Ensure win32 namespaces have two leading slashes so they are handled properly\n // by path.win32.parse() after being normalized.\n // https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#namespaces\n // UNC paths, paths starting with double slashes, e.g. \"\\\\\\\\wsl.localhost\\\\Ubuntu\\home\\\\\",\n // are okay to convert to forward slashes.\n // https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions\n let prefix = ''\n if (length > 4 && filepath.charCodeAt(3) === 92 /*'\\\\'*/) {\n const code2 = filepath.charCodeAt(2)\n // Look for \\\\?\\ or \\\\.\\\n if (\n (code2 === 63 /*'?'*/ || code2 === 46) /*'.'*/ &&\n filepath.charCodeAt(0) === 92 /*'\\\\'*/ &&\n filepath.charCodeAt(1) === 92 /*'\\\\'*/\n ) {\n start = 2\n prefix = '//'\n }\n }\n if (start === 0) {\n // Check for UNC paths first (\\\\server\\share or //server/share)\n // UNC paths must start with exactly two slashes, not more\n if (\n length > 2 &&\n ((filepath.charCodeAt(0) === 92 /*'\\\\'*/ &&\n filepath.charCodeAt(1) === 92 /*'\\\\'*/ &&\n filepath.charCodeAt(2) !== 92) /*'\\\\'*/ ||\n (filepath.charCodeAt(0) === 47 /*'/'*/ &&\n filepath.charCodeAt(1) === 47 /*'/'*/ &&\n filepath.charCodeAt(2) !== 47)) /*'/'*/\n ) {\n // Check if this is a valid UNC path: must have server/share format\n // Find the first segment (server name) and second segment (share name)\n let firstSegmentEnd = -1\n let hasSecondSegment = false\n\n // Skip leading slashes after the initial double slash\n let i = 2\n while (\n i < length &&\n (filepath.charCodeAt(i) === 47 /*'/'*/ ||\n filepath.charCodeAt(i) === 92) /*'\\\\'*/\n ) {\n i++\n }\n\n // Find the end of first segment (server name)\n while (i < length) {\n const char = filepath.charCodeAt(i)\n if (char === 47 /*'/'*/ || char === 92 /*'\\\\'*/) {\n firstSegmentEnd = i\n break\n }\n i++\n }\n\n if (firstSegmentEnd > 2) {\n // Skip slashes after server name\n i = firstSegmentEnd\n while (\n i < length &&\n (filepath.charCodeAt(i) === 47 /*'/'*/ ||\n filepath.charCodeAt(i) === 92) /*'\\\\'*/\n ) {\n i++\n }\n // Check if there's a share name (second segment)\n if (i < length) {\n hasSecondSegment = true\n }\n }\n\n if (firstSegmentEnd > 2 && hasSecondSegment) {\n // Valid UNC path - preserve double leading slashes\n start = 2\n prefix = '//'\n } else {\n // Just repeated slashes, treat as regular path\n code = filepath.charCodeAt(start)\n while (code === 47 /*'/'*/ || code === 92 /*'\\\\'*/) {\n start += 1\n code = filepath.charCodeAt(start)\n }\n if (start) {\n prefix = '/'\n }\n }\n } else {\n // Trim leading slashes for regular paths\n code = filepath.charCodeAt(start)\n while (code === 47 /*'/'*/ || code === 92 /*'\\\\'*/) {\n start += 1\n code = filepath.charCodeAt(start)\n }\n if (start) {\n prefix = '/'\n }\n }\n }\n let nextIndex = search(filepath, slashRegExp, { fromIndex: start })\n if (nextIndex === -1) {\n const segment = filepath.slice(start)\n if (segment === '.' || segment.length === 0) {\n return prefix || '.'\n }\n if (segment === '..') {\n return prefix ? prefix.slice(0, -1) || '/' : '..'\n }\n return prefix + segment\n }\n // Process segments and handle '.', '..', and empty segments.\n let collapsed = ''\n let segmentCount = 0\n let leadingDotDots = 0\n while (nextIndex !== -1) {\n const segment = filepath.slice(start, nextIndex)\n if (segment.length > 0 && segment !== '.') {\n if (segment === '..') {\n // Handle '..' by removing the last segment if possible.\n if (segmentCount > 0) {\n // Find the last separator and remove the last segment.\n const lastSeparatorIndex = collapsed.lastIndexOf('/')\n if (lastSeparatorIndex === -1) {\n // Only one segment, remove it entirely.\n collapsed = ''\n segmentCount = 0\n // Check if this was a leading '..', restore it.\n if (leadingDotDots > 0 && !prefix) {\n collapsed = '..'\n leadingDotDots = 1\n }\n } else {\n const lastSegmentStart = lastSeparatorIndex + 1\n const lastSegmentValue = collapsed.slice(lastSegmentStart)\n // Don't collapse leading '..' segments.\n if (lastSegmentValue === '..') {\n // Preserve the '..' and add another one.\n collapsed = `${collapsed}/${segment}`\n leadingDotDots += 1\n } else {\n // Normal collapse: remove the last segment.\n collapsed = collapsed.slice(0, lastSeparatorIndex)\n segmentCount -= 1\n }\n }\n } else if (!prefix) {\n // Preserve '..' for relative paths.\n collapsed = collapsed + (collapsed.length === 0 ? '' : '/') + segment\n leadingDotDots += 1\n }\n } else {\n collapsed = collapsed + (collapsed.length === 0 ? '' : '/') + segment\n segmentCount += 1\n }\n }\n start = nextIndex + 1\n code = filepath.charCodeAt(start)\n while (code === 47 /*'/'*/ || code === 92 /*'\\\\'*/) {\n start += 1\n code = filepath.charCodeAt(start)\n }\n nextIndex = search(filepath, slashRegExp, { fromIndex: start })\n }\n const lastSegment = filepath.slice(start)\n if (lastSegment.length > 0 && lastSegment !== '.') {\n if (lastSegment === '..') {\n if (segmentCount > 0) {\n const lastSeparatorIndex = collapsed.lastIndexOf('/')\n if (lastSeparatorIndex === -1) {\n collapsed = ''\n segmentCount = 0\n // Check if this was a leading '..', restore it.\n if (leadingDotDots > 0 && !prefix) {\n collapsed = '..'\n leadingDotDots = 1\n }\n } else {\n const lastSegmentStart = lastSeparatorIndex + 1\n const lastSegmentValue = collapsed.slice(lastSegmentStart)\n // Don't collapse leading '..' segments.\n if (lastSegmentValue === '..') {\n // Preserve the '..' and add another one.\n collapsed = `${collapsed}/${lastSegment}`\n leadingDotDots += 1\n } else {\n // Normal collapse: remove the last segment.\n collapsed = collapsed.slice(0, lastSeparatorIndex)\n segmentCount -= 1\n }\n }\n } else if (!prefix) {\n collapsed =\n collapsed + (collapsed.length === 0 ? '' : '/') + lastSegment\n leadingDotDots += 1\n }\n } else {\n collapsed = collapsed + (collapsed.length === 0 ? '' : '/') + lastSegment\n segmentCount += 1\n }\n }\n\n if (collapsed.length === 0) {\n return prefix || '.'\n }\n return prefix + collapsed\n}\n\n/**\n * Convert a path-like value to a string.\n *\n * Converts various path-like types (string, Buffer, URL) into a normalized\n * string representation. This function handles different input formats and\n * provides consistent string output for path operations.\n *\n * Supported input types:\n * - `string`: Returned as-is\n * - `Buffer`: Decoded as UTF-8 string\n * - `URL`: Converted using `fileURLToPath()`, with fallback for malformed URLs\n * - `null` / `undefined`: Returns empty string\n *\n * URL handling:\n * - Valid file URLs are converted via `url.fileURLToPath()`\n * - Malformed URLs fall back to pathname extraction with decoding\n * - Windows drive letters in URLs are handled specially\n * - Percent-encoded characters are decoded (e.g., `%20` becomes space)\n *\n * @param {string | Buffer | URL | null | undefined} pathLike - The path-like value to convert\n * @returns {string} The string representation of the path, or empty string for null/undefined\n *\n * @example\n * ```typescript\n * // String input\n * pathLikeToString('/home/user') // '/home/user'\n *\n * // Buffer input\n * pathLikeToString(Buffer.from('/tmp/file')) // '/tmp/file'\n *\n * // URL input\n * pathLikeToString(new URL('file:///home/user')) // '/home/user'\n * pathLikeToString(new URL('file:///C:/Windows')) // 'C:/Windows' (Windows)\n *\n * // Null/undefined input\n * pathLikeToString(null) // ''\n * pathLikeToString(undefined) // ''\n *\n * // Percent-encoded URLs\n * pathLikeToString(new URL('file:///path%20with%20spaces')) // '/path with spaces'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function pathLikeToString(\n pathLike: string | Buffer | URL | null | undefined,\n): string {\n if (pathLike === null || pathLike === undefined) {\n return ''\n }\n if (typeof pathLike === 'string') {\n return pathLike\n }\n const { Buffer } = getBuffer()\n if (Buffer.isBuffer(pathLike)) {\n return pathLike.toString('utf8')\n }\n const url = getUrl()\n if (pathLike instanceof URL) {\n try {\n return url.fileURLToPath(pathLike)\n } catch {\n // On Windows, file URLs like `file:///C:/path` include drive letters.\n // If a file URL is missing its drive letter (malformed), fileURLToPath() throws an error.\n // This fallback extracts the pathname directly from the URL object.\n //\n // Example flows:\n // - Unix: file:///home/user \u2192 pathname '/home/user' \u2192 keep as-is\n // - Windows valid: file:///C:/path \u2192 handled by fileURLToPath()\n // - Windows invalid: file:///path \u2192 pathname '/path' \u2192 strips to 'path'\n const pathname = pathLike.pathname\n\n // Decode percent-encoded characters (e.g., %20 \u2192 space).\n // The pathname property keeps URL encoding, but file paths need decoded characters.\n // This is not platform-specific; all URLs use percent-encoding regardless of OS.\n const decodedPathname = decodeURIComponent(pathname)\n\n // URL pathnames always start with `/`.\n // On Windows, strip the leading slash only for malformed URLs that lack drive letters\n // (e.g., `/path` should be `path`, but `/C:/path` should be `C:/path`).\n // On Unix, keep the leading slash for absolute paths (e.g., `/home/user`).\n const WIN32 = require('../constants/platform').WIN32\n if (WIN32 && decodedPathname.startsWith('/')) {\n // Check for drive letter pattern following Node.js source: /[a-zA-Z]:/\n // Character at index 1 should be a letter, character at index 2 should be ':'\n // Convert to lowercase\n const letter = decodedPathname.charCodeAt(1) | 0x20\n const hasValidDriveLetter =\n decodedPathname.length >= 3 &&\n letter >= 97 &&\n // 'a' to 'z'\n letter <= 122 &&\n decodedPathname.charAt(2) === ':'\n\n if (!hasValidDriveLetter) {\n // On Windows, preserve Unix-style absolute paths that don't start with a drive letter.\n // Only strip the leading slash for truly malformed Windows paths.\n // Since fileURLToPath() failed, this is likely a valid Unix-style absolute path.\n return decodedPathname\n }\n }\n return decodedPathname\n }\n }\n return String(pathLike)\n}\n\n/**\n * Split a path into an array of segments.\n *\n * Divides a path into individual components by splitting on path separators\n * (both forward slashes and backslashes). This is useful for path traversal,\n * analysis, and manipulation.\n *\n * The function handles:\n * - Forward slashes (`/`) on all platforms\n * - Backslashes (`\\`) on Windows\n * - Mixed separators in a single path\n * - Empty paths (returns empty array)\n *\n * Note: The resulting array may contain empty strings if the path has leading,\n * trailing, or consecutive separators (e.g., `/foo//bar/` becomes `['', 'foo', '', 'bar', '']`).\n *\n * @param {string | Buffer | URL} pathLike - The path to split\n * @returns {string[]} Array of path segments, or empty array for empty paths\n *\n * @example\n * ```typescript\n * // POSIX paths\n * splitPath('/home/user/file.txt') // ['', 'home', 'user', 'file.txt']\n * splitPath('src/lib/util.js') // ['src', 'lib', 'util.js']\n *\n * // Windows paths\n * splitPath('C:\\\\Users\\\\John') // ['C:', 'Users', 'John']\n * splitPath('folder\\\\file.txt') // ['folder', 'file.txt']\n *\n * // Mixed separators\n * splitPath('path/to\\\\file') // ['path', 'to', 'file']\n *\n * // Edge cases\n * splitPath('') // []\n * splitPath('/') // ['', '']\n * splitPath('/foo//bar/') // ['', 'foo', '', 'bar', '']\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function splitPath(pathLike: string | Buffer | URL): string[] {\n const filepath = pathLikeToString(pathLike)\n if (filepath === '') {\n return []\n }\n return filepath.split(slashRegExp)\n}\n\n/**\n * Remove leading ./ or ../ from a path.\n *\n * Strips the `./` or `.\\` prefix from relative paths. This is useful for\n * normalizing paths when the current directory reference is implicit or\n * unwanted.\n *\n * Note: This function only removes a single leading `./` or `.\\`. It does\n * not remove `../` prefixes or process the rest of the path.\n *\n * @param {string | Buffer | URL} pathLike - The path to process\n * @returns {string} The path without leading `./` or `.\\`, or unchanged if no such prefix\n *\n * @example\n * ```typescript\n * // Remove ./ prefix\n * trimLeadingDotSlash('./src/index.js') // 'src/index.js'\n * trimLeadingDotSlash('.\\\\src\\\\file.txt') // 'src\\\\file.txt'\n *\n * // Preserve ../ prefix\n * trimLeadingDotSlash('../lib/util.js') // '../lib/util.js'\n *\n * // No change for other paths\n * trimLeadingDotSlash('/absolute/path') // '/absolute/path'\n * trimLeadingDotSlash('relative/path') // 'relative/path'\n * trimLeadingDotSlash('.') // '.'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function trimLeadingDotSlash(pathLike: string | Buffer | URL): string {\n const filepath = pathLikeToString(pathLike)\n // Only trim ./ not ../\n if (filepath.startsWith('./') || filepath.startsWith('.\\\\')) {\n return filepath.slice(2)\n }\n return filepath\n}\n\n/**\n * Resolve an absolute path from path segments.\n *\n * This function mimics Node.js `path.resolve()` behavior by building an\n * absolute path from the given segments. It processes segments from right\n * to left, stopping when an absolute path is encountered. If no absolute\n * path is found, it prepends the current working directory.\n *\n * Algorithm:\n * 1. Process segments from right to left\n * 2. Stop when an absolute path is found\n * 3. Prepend current working directory if no absolute path found\n * 4. Normalize the final path\n *\n * Key behaviors:\n * - Later segments override earlier ones (e.g., `resolve('/foo', '/bar')` returns `/bar`)\n * - Empty or non-string segments are skipped\n * - Result is always an absolute path\n * - Path separators are normalized to forward slashes\n *\n * @param {...string} segments - Path segments to resolve\n * @returns {string} The resolved absolute path\n *\n * @example\n * ```typescript\n * // Basic resolution\n * resolve('foo', 'bar', 'baz') // '/cwd/foo/bar/baz' (assuming cwd is '/cwd')\n * resolve('/foo', 'bar', 'baz') // '/foo/bar/baz'\n * resolve('foo', '/bar', 'baz') // '/bar/baz'\n *\n * // Windows paths\n * resolve('C:\\\\foo', 'bar') // 'C:/foo/bar'\n *\n * // Empty segments\n * resolve('foo', '', 'bar') // '/cwd/foo/bar'\n * resolve() // '/cwd' (current directory)\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction resolve(...segments: string[]): string {\n let resolvedPath = ''\n let resolvedAbsolute = false\n\n // Process segments from right to left until we find an absolute path.\n // This allows later segments to override earlier ones.\n // Example: resolve('/foo', '/bar') returns '/bar', not '/foo/bar'.\n for (let i = segments.length - 1; i >= 0 && !resolvedAbsolute; i -= 1) {\n const segment = segments[i]\n\n // Skip empty or non-string segments.\n if (typeof segment !== 'string' || segment.length === 0) {\n continue\n }\n\n // Prepend the segment to the resolved path.\n // Use forward slashes as separators (normalized later).\n resolvedPath =\n segment + (resolvedPath.length === 0 ? '' : `/${resolvedPath}`)\n\n // Check if this segment is absolute.\n // Absolute paths stop the resolution process.\n resolvedAbsolute = isAbsolute(segment)\n }\n\n // If no absolute path was found in segments, prepend current working directory.\n // This ensures the final path is always absolute.\n if (!resolvedAbsolute) {\n const cwd = /*@__PURE__*/ require('node:process').cwd()\n resolvedPath = cwd + (resolvedPath.length === 0 ? '' : `/${resolvedPath}`)\n }\n\n // Normalize the resolved path (collapse '..' and '.', convert separators).\n return normalizePath(resolvedPath)\n}\n\n/**\n * Calculate the relative path from one path to another.\n *\n * This function computes how to get from the `from` path to the `to` path\n * using relative path notation. Both paths are first resolved to absolute\n * paths, then compared to find the common base path, and finally a relative\n * path is constructed using `../` for parent directory traversal.\n *\n * Algorithm:\n * 1. Resolve both paths to absolute\n * 2. Find the longest common path prefix (up to a separator)\n * 3. For each remaining directory in `from`, add `../` to go up\n * 4. Append the remaining path from `to`\n *\n * Windows-specific behavior:\n * - File system paths are case-insensitive on Windows (NTFS, FAT32)\n * - `C:\\Foo` and `c:\\foo` are considered the same path\n * - Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file\n * - Case is preserved but not significant for comparison\n *\n * @param {string} from - The source path (starting point)\n * @param {string} to - The destination path (target)\n * @returns {string} The relative path from `from` to `to`, or empty string if paths are identical\n *\n * @example\n * ```typescript\n * // Basic relative paths\n * relative('/foo/bar', '/foo/baz') // '../baz'\n * relative('/foo/bar/baz', '/foo') // '../..'\n * relative('/foo', '/foo/bar') // 'bar'\n *\n * // Same paths\n * relative('/foo/bar', '/foo/bar') // ''\n *\n * // Windows case-insensitive\n * relative('C:\\\\Foo\\\\bar', 'C:\\\\foo\\\\baz') // '../baz' (Windows)\n *\n * // Root paths\n * relative('/', '/foo/bar') // 'foo/bar'\n * relative('/foo/bar', '/') // '../..'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction relative(from: string, to: string): string {\n // Quick return if paths are already identical.\n if (from === to) {\n return ''\n }\n\n // Resolve both paths to absolute.\n // This handles relative paths, '.', '..', and ensures consistent format.\n const actualFrom = resolve(from)\n const actualTo = resolve(to)\n\n // Check again after resolution (paths might have been equivalent).\n if (actualFrom === actualTo) {\n return ''\n }\n\n const WIN32 = require('../constants/platform').WIN32\n\n // Windows: perform case-insensitive comparison.\n // NTFS and FAT32 preserve case but are case-insensitive for lookups.\n // This means 'C:\\Foo\\bar.txt' and 'c:\\foo\\BAR.TXT' refer to the same file.\n // Reference: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#case-sensitivity\n if (WIN32) {\n const fromLower = actualFrom.toLowerCase()\n const toLower = actualTo.toLowerCase()\n if (fromLower === toLower) {\n return ''\n }\n }\n\n // Skip the leading separator for comparison.\n // We compare paths starting after the root separator to find common directories.\n // Example: '/foo/bar' becomes 'foo/bar' for comparison (index 1).\n const fromStart = 1\n const fromEnd = actualFrom.length\n const fromLen = fromEnd - fromStart\n const toStart = 1\n const toEnd = actualTo.length\n const toLen = toEnd - toStart\n\n // Compare paths character by character to find the longest common prefix.\n // We only consider a common prefix valid if it ends at a directory separator.\n const length = fromLen < toLen ? fromLen : toLen\n // Index of last common directory separator.\n let lastCommonSep = -1\n let i = 0\n\n for (; i < length; i += 1) {\n let fromCode = actualFrom.charCodeAt(fromStart + i)\n let toCode = actualTo.charCodeAt(toStart + i)\n\n // Paths diverge at this character.\n // On Windows, perform case-insensitive comparison.\n if (WIN32) {\n // Normalize to lowercase for case-insensitive comparison.\n // Convert A-Z (65-90) to a-z (97-122).\n if (fromCode >= CHAR_UPPERCASE_A && fromCode <= CHAR_UPPERCASE_Z) {\n fromCode += 32\n }\n if (toCode >= CHAR_UPPERCASE_A && toCode <= CHAR_UPPERCASE_Z) {\n toCode += 32\n }\n }\n\n if (fromCode !== toCode) {\n break\n }\n\n // Track directory separators (both forward and backslash for Windows compatibility).\n // We need this to ensure we only split at directory boundaries.\n // Use original fromCode from actualFrom (before case normalization).\n if (isPathSeparator(actualFrom.charCodeAt(fromStart + i))) {\n lastCommonSep = i\n }\n }\n\n // Handle edge cases where one path is a prefix of the other.\n if (i === length) {\n if (toLen > length) {\n // Destination path is longer.\n const toCode = actualTo.charCodeAt(toStart + i)\n if (isPathSeparator(toCode)) {\n // `from` is the exact base path for `to`.\n // Example: from='/foo/bar'; to='/foo/bar/baz' \u2192 'baz'\n // Skip the separator character (+1) to get just the relative portion.\n return actualTo.slice(toStart + i + 1)\n }\n if (i === 0) {\n // `from` is the root directory.\n // Example: from='/'; to='/foo' \u2192 'foo'\n return actualTo.slice(toStart + i)\n }\n } else if (fromLen > length) {\n // Source path is longer.\n const fromCode = actualFrom.charCodeAt(fromStart + i)\n if (isPathSeparator(fromCode)) {\n // `to` is the exact base path for `from`.\n // Example: from='/foo/bar/baz'; to='/foo/bar' \u2192 '..'\n // We need to go up from the extra directory.\n lastCommonSep = i\n } else if (i === 0) {\n // `to` is the root directory.\n // Example: from='/foo'; to='/' \u2192 '..'\n lastCommonSep = 0\n }\n }\n }\n\n // Generate the relative path by constructing '../' segments.\n let out = ''\n\n // Count the number of directories in `from` after the common base.\n // For each directory, we need to go up one level ('../').\n // Example: from='/a/b/c', to='/a/x' \u2192 common='a', need '../..' (up from c, up from b)\n for (i = fromStart + lastCommonSep + 1; i <= fromEnd; i += 1) {\n const code = actualFrom.charCodeAt(i)\n\n // At the end of the path or at a separator, add '../'.\n if (i === fromEnd || isPathSeparator(code)) {\n out += out.length === 0 ? '..' : '/..'\n }\n }\n\n // Append the rest of the destination path after the common base.\n // This gives us the path from the common ancestor to the destination.\n return out + actualTo.slice(toStart + lastCommonSep)\n}\n\n/**\n * Get the relative path from one path to another.\n *\n * Computes the relative path from `from` to `to` and normalizes the result.\n * This is a convenience wrapper around the `relative()` function that adds\n * path normalization (converting separators and collapsing segments).\n *\n * The function:\n * 1. Calculates the relative path using `relative()`\n * 2. Normalizes the result using `normalizePath()`\n * 3. Preserves empty strings (same path) without converting to `.`\n *\n * @param {string} from - The source path (starting point)\n * @param {string} to - The destination path (target)\n * @returns {string} The normalized relative path from `from` to `to`, or empty string if paths are identical\n *\n * @example\n * ```typescript\n * // Basic usage\n * relativeResolve('/foo/bar', '/foo/baz') // '../baz'\n * relativeResolve('/foo/bar/baz', '/foo') // '../..'\n * relativeResolve('/foo', '/foo/bar') // 'bar'\n *\n * // Same paths\n * relativeResolve('/foo/bar', '/foo/bar') // ''\n *\n * // Windows paths (normalized)\n * relativeResolve('C:\\\\foo\\\\bar', 'C:\\\\foo\\\\baz') // '../baz'\n *\n * // With normalization\n * relativeResolve('/foo/./bar', '/foo/baz') // '../baz'\n * relativeResolve('/foo/bar/../baz', '/foo/qux') // '../qux'\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function relativeResolve(from: string, to: string): string {\n const rel = relative(from, to)\n // Empty string means same path - don't normalize to '.'\n if (rel === '') {\n return ''\n }\n return normalizePath(rel)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Buffer", "WIN32"]
|
|
7
7
|
}
|
package/dist/paths.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/paths.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @fileoverview Path utilities for Socket ecosystem directories.\n * Provides platform-aware path resolution for Socket tools' shared directory structure.\n *\n * Directory Structure:\n * ~/.socket/\n * \u251C\u2500\u2500 _cacache/ # Content-addressable cache
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview Path utilities for Socket ecosystem directories.\n * Provides platform-aware path resolution for Socket tools' shared directory structure.\n *\n * Directory Structure:\n * ~/.socket/\n * \u251C\u2500\u2500 _cacache/ # Content-addressable cache for npm packages\n * \u251C\u2500\u2500 _dlx/ # DLX installations (content-addressed by hash)\n * \u2502 \u251C\u2500\u2500 <hash>/ # npm package installs (dlx-package)\n * \u2502 \u2514\u2500\u2500 <hash>/ # binary downloads (dlx-binary)\n * \u251C\u2500\u2500 _socket/ # Socket CLI app directory\n * \u251C\u2500\u2500 _registry/ # Socket Registry app directory\n * \u2514\u2500\u2500 _sfw/ # Socket Firewall app directory\n */\n\nimport * as os from 'node:os'\nimport * as path from 'node:path'\n\nimport { SOCKET_CACACHE_DIR } from '#env/socket-cacache-dir'\n\nimport { normalizePath } from './path'\n\n/**\n * Get the Socket home directory (~/.socket).\n * Alias for getSocketUserDir() for consistency across Socket projects.\n */\nexport function getSocketHomePath(): string {\n return getSocketUserDir()\n}\n\n/**\n * Get the Socket user directory (~/.socket).\n */\nexport function getSocketUserDir(): string {\n return normalizePath(\n path.join(\n os.homedir(),\n /*@__INLINE__*/ require('./constants/paths').DOT_SOCKET_DIR,\n ),\n )\n}\n\n/**\n * Get a Socket app directory (~/.socket/_<appName>).\n */\nexport function getSocketAppDir(appName: string): string {\n return normalizePath(\n path.join(\n getSocketUserDir(),\n `${/*@__INLINE__*/ require('./constants/socket').SOCKET_APP_PREFIX}${appName}`,\n ),\n )\n}\n\n/**\n * Get the Socket cacache directory (~/.socket/_cacache).\n * Can be overridden with SOCKET_CACACHE_DIR environment variable for testing.\n */\nexport function getSocketCacacheDir(): string {\n if (SOCKET_CACACHE_DIR) {\n return normalizePath(SOCKET_CACACHE_DIR)\n }\n return normalizePath(\n path.join(\n getSocketUserDir(),\n `${/*@__INLINE__*/ require('./constants/socket').SOCKET_APP_PREFIX}cacache`,\n ),\n )\n}\n\n/**\n * Get the Socket DLX directory (~/.socket/_dlx).\n */\nexport function getSocketDlxDir(): string {\n return normalizePath(\n path.join(\n getSocketUserDir(),\n `${/*@__INLINE__*/ require('./constants/socket').SOCKET_APP_PREFIX}${/*@__INLINE__*/ require('./constants/socket').SOCKET_DLX_APP_NAME}`,\n ),\n )\n}\n\n/**\n * Get a Socket app cache directory (~/.socket/_<appName>/cache).\n */\nexport function getSocketAppCacheDir(appName: string): string {\n return normalizePath(\n path.join(\n getSocketAppDir(appName),\n /*@__INLINE__*/ require('./constants/paths').CACHE_DIR,\n ),\n )\n}\n\n/**\n * Get a Socket app TTL cache directory (~/.socket/_<appName>/cache/ttl).\n */\nexport function getSocketAppCacheTtlDir(appName: string): string {\n return normalizePath(\n path.join(\n getSocketAppCacheDir(appName),\n /*@__INLINE__*/ require('./constants/paths').CACHE_TTL_DIR,\n ),\n )\n}\n\n/**\n * Get the Socket CLI directory (~/.socket/_socket).\n */\nexport function getSocketCliDir(): string {\n return getSocketAppDir(\n /*@__INLINE__*/ require('./constants/socket').SOCKET_CLI_APP_NAME,\n )\n}\n\n/**\n * Get the Socket Registry directory (~/.socket/_registry).\n */\nexport function getSocketRegistryDir(): string {\n return getSocketAppDir(\n /*@__INLINE__*/ require('./constants/socket').SOCKET_REGISTRY_APP_NAME,\n )\n}\n\n/**\n * Get the Socket Registry GitHub cache directory (~/.socket/_registry/cache/ttl/github).\n */\nexport function getSocketRegistryGithubCacheDir(): string {\n return normalizePath(\n path.join(\n getSocketAppCacheTtlDir(\n /*@__INLINE__*/ require('./constants/socket').SOCKET_REGISTRY_APP_NAME,\n ),\n /*@__INLINE__*/ require('./constants/github').CACHE_GITHUB_DIR,\n ),\n )\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA,SAAoB;AACpB,WAAsB;AAEtB,gCAAmC;AAEnC,kBAA8B;AAMvB,SAAS,oBAA4B;AAC1C,SAAO,iBAAiB;AAC1B;AAKO,SAAS,mBAA2B;AACzC,aAAO;AAAA,IACL,KAAK;AAAA,MACH,GAAG,QAAQ;AAAA;AAAA,MACK,QAAQ,mBAAmB,EAAE;AAAA,IAC/C;AAAA,EACF;AACF;AAKO,SAAS,gBAAgB,SAAyB;AACvD,aAAO;AAAA,IACL,KAAK;AAAA,MACH,iBAAiB;AAAA,MACjB;AAAA,MAAmB,QAAQ,oBAAoB,EAAE,iBAAiB,GAAG,OAAO;AAAA,IAC9E;AAAA,EACF;AACF;AAMO,SAAS,sBAA8B;AAC5C,MAAI,8CAAoB;AACtB,eAAO,2BAAc,4CAAkB;AAAA,EACzC;AACA,aAAO;AAAA,IACL,KAAK;AAAA,MACH,iBAAiB;AAAA,MACjB;AAAA,MAAmB,QAAQ,oBAAoB,EAAE,iBAAiB;AAAA,IACpE;AAAA,EACF;AACF;AAKO,SAAS,kBAA0B;AACxC,aAAO;AAAA,IACL,KAAK;AAAA,MACH,iBAAiB;AAAA,MACjB;AAAA,MAAmB,QAAQ,oBAAoB,EAAE,iBAAiB;AAAA,MAAmB,QAAQ,oBAAoB,EAAE,mBAAmB;AAAA,IACxI;AAAA,EACF;AACF;AAKO,SAAS,qBAAqB,SAAyB;AAC5D,aAAO;AAAA,IACL,KAAK;AAAA,MACH,gBAAgB,OAAO;AAAA;AAAA,MACP,QAAQ,mBAAmB,EAAE;AAAA,IAC/C;AAAA,EACF;AACF;AAKO,SAAS,wBAAwB,SAAyB;AAC/D,aAAO;AAAA,IACL,KAAK;AAAA,MACH,qBAAqB,OAAO;AAAA;AAAA,MACZ,QAAQ,mBAAmB,EAAE;AAAA,IAC/C;AAAA,EACF;AACF;AAKO,SAAS,kBAA0B;AACxC,SAAO;AAAA;AAAA,IACW,QAAQ,oBAAoB,EAAE;AAAA,EAChD;AACF;AAKO,SAAS,uBAA+B;AAC7C,SAAO;AAAA;AAAA,IACW,QAAQ,oBAAoB,EAAE;AAAA,EAChD;AACF;AAKO,SAAS,kCAA0C;AACxD,aAAO;AAAA,IACL,KAAK;AAAA,MACH;AAAA;AAAA,QACkB,QAAQ,oBAAoB,EAAE;AAAA,MAChD;AAAA;AAAA,MACgB,QAAQ,oBAAoB,EAAE;AAAA,IAChD;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -21,6 +21,7 @@ __export(temporary_executor_exports, {
|
|
|
21
21
|
isRunningInTemporaryExecutor: () => isRunningInTemporaryExecutor
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(temporary_executor_exports);
|
|
24
|
+
var import_platform = require("#constants/platform");
|
|
24
25
|
var import_path = require("./path");
|
|
25
26
|
function isRunningInTemporaryExecutor(cwd = process.cwd()) {
|
|
26
27
|
const userAgent = process.env["npm_config_user_agent"];
|
|
@@ -42,7 +43,7 @@ function isRunningInTemporaryExecutor(cwd = process.cwd()) {
|
|
|
42
43
|
// Yarn Berry PnP virtual packages.
|
|
43
44
|
".yarn/$$"
|
|
44
45
|
];
|
|
45
|
-
if (
|
|
46
|
+
if (import_platform.WIN32) {
|
|
46
47
|
tempPatterns.push("AppData/Local/Temp/xfs-");
|
|
47
48
|
}
|
|
48
49
|
return tempPatterns.some((pattern) => normalizedCwd.includes(pattern));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/temporary-executor.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @fileoverview Temporary package executor detection utilities for Socket ecosystem.\n * Identifies and handles temporary execution contexts such as npx, pnpm dlx, and yarn dlx.\n */\n\nimport { normalizePath } from './path'\n\n/**\n * Detects if the current process is running in a temporary package execution context\n * such as npm exec, npx, pnpm dlx, or yarn dlx.\n *\n * When package managers run commands via exec/npx/dlx, they execute in temporary directories\n * that are cleaned up after execution. Creating persistent shadows or modifying PATH\n * in these contexts can break subsequent package manager commands.\n */\nexport function isRunningInTemporaryExecutor(cwd = process.cwd()): boolean {\n // Check environment variable for exec/npx/dlx indicators.\n const userAgent = process.env['npm_config_user_agent']\n if (\n userAgent?.includes('exec') ||\n userAgent?.includes('npx') ||\n userAgent?.includes('dlx')\n ) {\n return true\n }\n\n // Normalize the cwd path for consistent checking across platforms.\n const normalizedCwd = normalizePath(cwd)\n\n // Check if running from npm's npx cache.\n const npmCache = process.env['npm_config_cache']\n if (npmCache && normalizedCwd.includes(normalizePath(npmCache))) {\n return true\n }\n\n // Check common temporary execution path patterns.\n const tempPatterns = [\n // npm's npx cache directory\n '_npx',\n // pnpm dlx temporary store\n '.pnpm-store',\n // Common dlx directory prefix\n 'dlx-',\n // Yarn Berry PnP virtual packages.\n '.yarn/$$',\n ]\n\n // Yarn on Windows uses AppData/Local/Temp/xfs- pattern.\n if (
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,kBAA8B;AAUvB,SAAS,6BAA6B,MAAM,QAAQ,IAAI,GAAY;AAEzE,QAAM,YAAY,QAAQ,IAAI,uBAAuB;AACrD,MACE,WAAW,SAAS,MAAM,KAC1B,WAAW,SAAS,KAAK,KACzB,WAAW,SAAS,KAAK,GACzB;AACA,WAAO;AAAA,EACT;AAGA,QAAM,oBAAgB,2BAAc,GAAG;AAGvC,QAAM,WAAW,QAAQ,IAAI,kBAAkB;AAC/C,MAAI,YAAY,cAAc,aAAS,2BAAc,QAAQ,CAAC,GAAG;AAC/D,WAAO;AAAA,EACT;AAGA,QAAM,eAAe;AAAA;AAAA,IAEnB;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,EACF;AAGA,MAAI,
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview Temporary package executor detection utilities for Socket ecosystem.\n * Identifies and handles temporary execution contexts such as npx, pnpm dlx, and yarn dlx.\n */\n\nimport { WIN32 } from '#constants/platform'\nimport { normalizePath } from './path'\n\n/**\n * Detects if the current process is running in a temporary package execution context\n * such as npm exec, npx, pnpm dlx, or yarn dlx.\n *\n * When package managers run commands via exec/npx/dlx, they execute in temporary directories\n * that are cleaned up after execution. Creating persistent shadows or modifying PATH\n * in these contexts can break subsequent package manager commands.\n */\nexport function isRunningInTemporaryExecutor(cwd = process.cwd()): boolean {\n // Check environment variable for exec/npx/dlx indicators.\n const userAgent = process.env['npm_config_user_agent']\n if (\n userAgent?.includes('exec') ||\n userAgent?.includes('npx') ||\n userAgent?.includes('dlx')\n ) {\n return true\n }\n\n // Normalize the cwd path for consistent checking across platforms.\n const normalizedCwd = normalizePath(cwd)\n\n // Check if running from npm's npx cache.\n const npmCache = process.env['npm_config_cache']\n if (npmCache && normalizedCwd.includes(normalizePath(npmCache))) {\n return true\n }\n\n // Check common temporary execution path patterns.\n const tempPatterns = [\n // npm's npx cache directory\n '_npx',\n // pnpm dlx temporary store\n '.pnpm-store',\n // Common dlx directory prefix\n 'dlx-',\n // Yarn Berry PnP virtual packages.\n '.yarn/$$',\n ]\n\n // Yarn on Windows uses AppData/Local/Temp/xfs- pattern.\n if (WIN32) {\n tempPatterns.push('AppData/Local/Temp/xfs-')\n }\n\n return tempPatterns.some(pattern => normalizedCwd.includes(pattern))\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,sBAAsB;AACtB,kBAA8B;AAUvB,SAAS,6BAA6B,MAAM,QAAQ,IAAI,GAAY;AAEzE,QAAM,YAAY,QAAQ,IAAI,uBAAuB;AACrD,MACE,WAAW,SAAS,MAAM,KAC1B,WAAW,SAAS,KAAK,KACzB,WAAW,SAAS,KAAK,GACzB;AACA,WAAO;AAAA,EACT;AAGA,QAAM,oBAAgB,2BAAc,GAAG;AAGvC,QAAM,WAAW,QAAQ,IAAI,kBAAkB;AAC/C,MAAI,YAAY,cAAc,aAAS,2BAAc,QAAQ,CAAC,GAAG;AAC/D,WAAO;AAAA,EACT;AAGA,QAAM,eAAe;AAAA;AAAA,IAEnB;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,EACF;AAGA,MAAI,uBAAO;AACT,iBAAa,KAAK,yBAAyB;AAAA,EAC7C;AAEA,SAAO,aAAa,KAAK,aAAW,cAAc,SAAS,OAAO,CAAC;AACrE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|