-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstaged.ts
More file actions
193 lines (187 loc) · 6.31 KB
/
staged.ts
File metadata and controls
193 lines (187 loc) · 6.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/**
* @fileoverview "Ready for the next commit" helpers — `git diff --cached`
* over only the index. Excludes unstaged tracked-file edits and untracked
* paths; use `changed.ts` if you need the broader view.
*/
import { normalizePath } from '../paths/normalize'
import { ArrayPrototypeIncludes } from '../primordials/array'
import { getGitDiffSpawnArgs, innerDiff, innerDiffSync } from './_internal'
import { getCachedRealpath, getCwd, getPath } from './repo'
import type { GitDiffOptions } from './types'
/**
* Get staged files ready for commit (changes added with `git add`).
*
* Uses `git diff --cached --name-only` which returns only staged changes.
* Does NOT include:
* - Unstaged modifications (changes not added with `git add`)
* - Untracked files (new files not added to git)
*
* This is a focused check for what will be included in the next commit.
* Useful for validating changes before committing or running pre-commit hooks.
*
* @param options - Options controlling path format and filtering.
* @returns Promise resolving to array of staged file paths.
*
* @example
* ```typescript
* // Get currently staged files
* const files = await getStagedFiles()
* // => ['src/foo.ts']
*
* // Stage more files
* await spawn('git', ['add', 'src/bar.ts'])
* const files = await getStagedFiles()
* // => ['src/foo.ts', 'src/bar.ts']
*
* // Get absolute paths
* const files = await getStagedFiles({ absolute: true })
* // => ['/path/to/repo/src/foo.ts', ...]
* ```
*/
export async function getStagedFiles(
options?: GitDiffOptions | undefined,
): Promise<string[]> {
const args = getGitDiffSpawnArgs(options?.cwd).staged
return await innerDiff(args, options)
}
/**
* Get staged files ready for commit (changes added with `git add`).
*
* Synchronous version of `getStagedFiles()`. Uses `git diff --cached --name-only`
* which returns only staged changes. Does NOT include:
* - Unstaged modifications (changes not added with `git add`)
* - Untracked files (new files not added to git)
*
* This is a focused check for what will be included in the next commit.
* Useful for validating changes before committing or running pre-commit hooks.
*
* @param options - Options controlling path format and filtering.
* @returns Array of staged file paths.
*
* @example
* ```typescript
* // Get currently staged files
* const files = getStagedFilesSync()
* // => ['src/foo.ts']
*
* // Stage more files
* spawnSync('git', ['add', 'src/bar.ts'])
* const files = getStagedFilesSync()
* // => ['src/foo.ts', 'src/bar.ts']
*
* // Get absolute paths
* const files = getStagedFilesSync({ absolute: true })
* // => ['/path/to/repo/src/foo.ts', ...]
* ```
*/
export function getStagedFilesSync(
options?: GitDiffOptions | undefined,
): string[] {
const args = getGitDiffSpawnArgs(options?.cwd).staged
return innerDiffSync(args, options)
}
/**
* Check if a file or directory is staged for commit.
*
* Checks if the given pathname has changes staged with `git add` that will
* be included in the next commit. Does NOT include:
* - Unstaged modifications (changes not added with `git add`)
* - Untracked files (new files not in git)
*
* For directories, returns `true` if ANY file within the directory is staged.
*
* Symlinks in the pathname and cwd are automatically resolved using
* `fs.realpathSync()` before comparison.
*
* @param pathname - File or directory path to check.
* @param options - Options for the git diff check.
* @returns Promise resolving to `true` if path is staged, `false` otherwise.
*
* @example
* ```typescript
* // Check if file is staged
* const staged = await isStaged('src/foo.ts')
* // => false
*
* // Stage the file
* await spawn('git', ['add', 'src/foo.ts'])
* const staged = await isStaged('src/foo.ts')
* // => true
*
* // Check directory
* const staged = await isStaged('src/')
* // => true (if any file in src/ is staged)
* ```
*/
export async function isStaged(
pathname: string,
options?: GitDiffOptions | undefined,
): Promise<boolean> {
const files = await getStagedFiles({
__proto__: null,
...options,
absolute: false,
})
const path = getPath()
// Resolve pathname to handle symlinks before computing relative path (using cache).
const resolvedPathname = getCachedRealpath(pathname)
// options.cwd-passed arm exercised when caller specifies cwd; default getCwd().
/* c8 ignore start */
const baseCwd = options?.cwd ? getCachedRealpath(options['cwd']) : getCwd()
/* c8 ignore stop */
const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))
return ArrayPrototypeIncludes(files, relativePath)
}
/**
* Check if a file or directory is staged for commit.
*
* Synchronous version of `isStaged()`. Checks if the given pathname has
* changes staged with `git add` that will be included in the next commit.
* Does NOT include:
* - Unstaged modifications (changes not added with `git add`)
* - Untracked files (new files not in git)
*
* For directories, returns `true` if ANY file within the directory is staged.
*
* Symlinks in the pathname and cwd are automatically resolved using
* `fs.realpathSync()` before comparison.
*
* @param pathname - File or directory path to check.
* @param options - Options for the git diff check.
* @returns `true` if path is staged, `false` otherwise.
*
* @example
* ```typescript
* // Check if file is staged
* const staged = isStagedSync('src/foo.ts')
* // => false
*
* // Stage the file
* spawnSync('git', ['add', 'src/foo.ts'])
* const staged = isStagedSync('src/foo.ts')
* // => true
*
* // Check directory
* const staged = isStagedSync('src/')
* // => true (if any file in src/ is staged)
* ```
*/
export function isStagedSync(
pathname: string,
options?: GitDiffOptions | undefined,
): boolean {
const files = getStagedFilesSync({
__proto__: null,
...options,
absolute: false,
})
const path = getPath()
// Resolve pathname to handle symlinks before computing relative path (using cache).
const resolvedPathname = getCachedRealpath(pathname)
// options.cwd-passed arm exercised when caller specifies cwd; default getCwd().
/* c8 ignore start */
const baseCwd = options?.cwd ? getCachedRealpath(options['cwd']) : getCwd()
/* c8 ignore stop */
const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))
return ArrayPrototypeIncludes(files, relativePath)
}