ts-repo-utils 6.1.0 → 6.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/README.md +11 -7
- package/dist/cmd/assert-repo-is-clean.mjs +1 -1
- package/dist/cmd/check-should-run-type-checks.mjs +1 -1
- package/dist/cmd/format-diff-from.mjs +29 -8
- package/dist/cmd/format-diff-from.mjs.map +1 -1
- package/dist/cmd/format-uncommitted.d.mts +3 -0
- package/dist/cmd/format-uncommitted.d.mts.map +1 -0
- package/dist/cmd/format-uncommitted.mjs +59 -0
- package/dist/cmd/format-uncommitted.mjs.map +1 -0
- package/dist/cmd/gen-index-ts.mjs +1 -1
- package/dist/functions/diff.d.mts +32 -2
- package/dist/functions/diff.d.mts.map +1 -1
- package/dist/functions/diff.mjs +47 -29
- package/dist/functions/diff.mjs.map +1 -1
- package/dist/functions/exec-async.d.mts +2 -2
- package/dist/functions/exec-async.d.mts.map +1 -1
- package/dist/functions/format.d.mts +20 -11
- package/dist/functions/format.d.mts.map +1 -1
- package/dist/functions/format.mjs +134 -95
- package/dist/functions/format.mjs.map +1 -1
- package/dist/functions/index.mjs +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +2 -2
- package/src/cmd/assert-repo-is-clean.mts +1 -1
- package/src/cmd/check-should-run-type-checks.mts +1 -1
- package/src/cmd/format-diff-from.mts +35 -9
- package/src/cmd/format-uncommitted.mts +67 -0
- package/src/cmd/gen-index-ts.mts +1 -1
- package/src/functions/diff.mts +85 -32
- package/src/functions/diff.test.mts +569 -102
- package/src/functions/exec-async.mts +2 -2
- package/src/functions/exec-async.test.mts +77 -47
- package/src/functions/format.mts +224 -141
- package/src/functions/format.test.mts +625 -20
- package/src/functions/workspace-utils/run-cmd-in-stages.test.mts +266 -0
- package/dist/cmd/format-untracked.d.mts +0 -3
- package/dist/cmd/format-untracked.d.mts.map +0 -1
- package/dist/cmd/format-untracked.mjs +0 -34
- package/dist/cmd/format-untracked.mjs.map +0 -1
- package/src/cmd/format-untracked.mts +0 -31
|
@@ -9,9 +9,9 @@ type ExecOptionsCustom = Readonly<{
|
|
|
9
9
|
silent?: boolean;
|
|
10
10
|
}>;
|
|
11
11
|
|
|
12
|
-
type ExecOptions = DeepReadonly<ExecOptions_ & ExecOptionsCustom>;
|
|
12
|
+
export type ExecOptions = DeepReadonly<ExecOptions_ & ExecOptionsCustom>;
|
|
13
13
|
|
|
14
|
-
type ExecResult<T extends string | Buffer> = Result<
|
|
14
|
+
export type ExecResult<T extends string | Buffer> = Result<
|
|
15
15
|
Readonly<{ stdout: T; stderr: T }>,
|
|
16
16
|
ExecException
|
|
17
17
|
>;
|
|
@@ -448,53 +448,83 @@ describe('exec-async', () => {
|
|
|
448
448
|
});
|
|
449
449
|
|
|
450
450
|
test('should demonstrate type equivalence with runtime comparison', async () => {
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
451
|
+
// Mock console functions to suppress output
|
|
452
|
+
const consoleLogSpy = vi
|
|
453
|
+
// eslint-disable-next-line vitest/no-restricted-vi-methods
|
|
454
|
+
.spyOn(console, 'log')
|
|
455
|
+
.mockImplementation(() => {});
|
|
456
|
+
|
|
457
|
+
const consoleErrorSpy = vi
|
|
458
|
+
// eslint-disable-next-line vitest/no-restricted-vi-methods
|
|
459
|
+
.spyOn(console, 'error')
|
|
460
|
+
.mockImplementation(() => {});
|
|
461
|
+
|
|
462
|
+
const stderrWriteSpy = vi
|
|
463
|
+
// eslint-disable-next-line vitest/no-restricted-vi-methods
|
|
464
|
+
.spyOn(process.stderr, 'write')
|
|
465
|
+
.mockImplementation(() => true);
|
|
466
|
+
|
|
467
|
+
try {
|
|
468
|
+
await withSilentEcho(async () => {
|
|
469
|
+
// Create a type that represents what exec callback receives
|
|
470
|
+
type ExecCallbackParams<T extends string | Buffer> = {
|
|
471
|
+
error: ExecException | null;
|
|
472
|
+
stdout: T;
|
|
473
|
+
stderr: T;
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
// Helper to capture exec callback types
|
|
477
|
+
const captureExecTypes = <T extends string | Buffer>(
|
|
478
|
+
_encoding?: BufferEncoding | 'buffer' | null,
|
|
479
|
+
): ExecCallbackParams<T> => {
|
|
480
|
+
const emptyParams: ExecCallbackParams<T> = {
|
|
481
|
+
error: null,
|
|
482
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
483
|
+
stdout: undefined as unknown as T,
|
|
484
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
485
|
+
stderr: undefined as unknown as T,
|
|
486
|
+
};
|
|
487
|
+
return emptyParams;
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
// Default encoding comparison
|
|
491
|
+
const _execDefault = captureExecTypes<string>();
|
|
492
|
+
const $Default = await $('echo "test"', { silent: true });
|
|
493
|
+
if (Result.isOk($Default)) {
|
|
494
|
+
expectType<
|
|
495
|
+
typeof _execDefault.stdout,
|
|
496
|
+
typeof $Default.value.stdout
|
|
497
|
+
>('=');
|
|
498
|
+
expectType<
|
|
499
|
+
typeof _execDefault.stderr,
|
|
500
|
+
typeof $Default.value.stderr
|
|
501
|
+
>('=');
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Buffer encoding comparison
|
|
505
|
+
const _execBuffer = captureExecTypes<Buffer>('buffer');
|
|
506
|
+
const $Buffer = await $('echo "test"', {
|
|
507
|
+
encoding: 'buffer',
|
|
508
|
+
silent: true,
|
|
509
|
+
});
|
|
510
|
+
if (Result.isOk($Buffer)) {
|
|
511
|
+
expectType<typeof _execBuffer.stdout, typeof $Buffer.value.stdout>(
|
|
512
|
+
'=',
|
|
513
|
+
);
|
|
514
|
+
expectType<typeof _execBuffer.stderr, typeof $Buffer.value.stderr>(
|
|
515
|
+
'=',
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Error type comparison
|
|
520
|
+
if (Result.isErr($Default)) {
|
|
521
|
+
expectType<ExecException, typeof $Default.value>('=');
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
} finally {
|
|
525
|
+
consoleLogSpy.mockRestore();
|
|
526
|
+
consoleErrorSpy.mockRestore();
|
|
527
|
+
stderrWriteSpy.mockRestore();
|
|
498
528
|
}
|
|
499
529
|
});
|
|
500
530
|
});
|
package/src/functions/format.mts
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
|
+
import { type ExecException } from 'node:child_process';
|
|
1
2
|
import * as prettier from 'prettier';
|
|
2
|
-
import { Arr, Result } from 'ts-data-forge';
|
|
3
|
+
import { Arr, isNotUndefined, Result } from 'ts-data-forge';
|
|
3
4
|
import '../node-global.mjs';
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getDiffFrom,
|
|
7
|
+
getModifiedFiles,
|
|
8
|
+
getStagedFiles,
|
|
9
|
+
getUntrackedFiles,
|
|
10
|
+
} from './diff.mjs';
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
13
|
* Format a list of files using Prettier
|
|
8
14
|
*
|
|
9
15
|
* @param files - Array of file paths to format
|
|
10
|
-
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
11
16
|
*/
|
|
12
|
-
export const
|
|
17
|
+
export const formatFiles = async (
|
|
13
18
|
files: readonly string[],
|
|
14
19
|
options?: Readonly<{ silent?: boolean }>,
|
|
15
|
-
): Promise<
|
|
20
|
+
): Promise<Result<undefined, readonly unknown[]>> => {
|
|
16
21
|
const silent = options?.silent ?? false;
|
|
17
22
|
|
|
18
23
|
if (files.length === 0) {
|
|
19
24
|
if (!silent) {
|
|
20
25
|
echo('No files to format');
|
|
21
26
|
}
|
|
22
|
-
return
|
|
27
|
+
return Result.ok(undefined);
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
if (!silent) {
|
|
@@ -27,62 +32,97 @@ export const formatFilesList = async (
|
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
// Format each file
|
|
30
|
-
const results
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
const results: readonly PromiseSettledResult<Result<undefined, unknown>>[] =
|
|
36
|
+
// NOTE: Using Promise.allSettled to ensure all files are processed even if some fail
|
|
37
|
+
await Promise.allSettled(
|
|
38
|
+
files.map(async (filePath) => {
|
|
39
|
+
try {
|
|
40
|
+
// Check if file exists first
|
|
41
|
+
try {
|
|
42
|
+
await fs.access(filePath);
|
|
43
|
+
} catch {
|
|
44
|
+
// File doesn't exist, skip it
|
|
45
|
+
if (!silent) {
|
|
46
|
+
echo(`Skipping non-existent file: ${filePath}`);
|
|
47
|
+
}
|
|
48
|
+
return Result.ok(undefined);
|
|
49
|
+
}
|
|
35
50
|
|
|
36
|
-
|
|
37
|
-
|
|
51
|
+
// Read file content
|
|
52
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
38
53
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
ignorePath: '.prettierignore',
|
|
42
|
-
});
|
|
54
|
+
// Resolve prettier config for this file
|
|
55
|
+
const prettierOptions = await prettier.resolveConfig(filePath);
|
|
43
56
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
// Check if file is ignored by prettier
|
|
58
|
+
const fileInfo = await prettier.getFileInfo(filePath, {
|
|
59
|
+
ignorePath: '.prettierignore',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (fileInfo.ignored) {
|
|
63
|
+
if (!silent) {
|
|
64
|
+
echo(`Skipping ignored file: ${filePath}`);
|
|
65
|
+
}
|
|
66
|
+
return Result.ok(undefined);
|
|
47
67
|
}
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
68
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
69
|
+
// Format the content
|
|
70
|
+
const formatted = await prettier.format(content, {
|
|
71
|
+
...prettierOptions,
|
|
72
|
+
filepath: filePath,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Only write if content changed
|
|
76
|
+
if (formatted === content) {
|
|
77
|
+
if (!silent) {
|
|
78
|
+
echo(`Unchanged: ${filePath}`);
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
await fs.writeFile(filePath, formatted, 'utf8');
|
|
82
|
+
if (!silent) {
|
|
83
|
+
echo(`Formatted: ${filePath}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
56
86
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
await fs.writeFile(filePath, formatted, 'utf8');
|
|
87
|
+
return Result.ok(undefined);
|
|
88
|
+
} catch (error) {
|
|
60
89
|
if (!silent) {
|
|
61
|
-
|
|
90
|
+
console.error(`Error formatting ${filePath}:`, error);
|
|
62
91
|
}
|
|
92
|
+
return Result.err(error);
|
|
63
93
|
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
if (results.every((r) => r.status === 'fulfilled')) {
|
|
98
|
+
const fulfilled = results.map((r) => r.value);
|
|
99
|
+
if (fulfilled.every(Result.isOk)) {
|
|
100
|
+
return Result.ok(undefined);
|
|
101
|
+
} else {
|
|
102
|
+
const errors: readonly unknown[] = fulfilled
|
|
103
|
+
.filter(Result.isErr)
|
|
104
|
+
.map((r) => r.value);
|
|
105
|
+
|
|
106
|
+
return Result.err(errors);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
const errors: readonly unknown[] = results
|
|
110
|
+
.filter((r) => r.status === 'rejected')
|
|
111
|
+
.map((r) => r.reason as unknown);
|
|
70
112
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return hasErrors ? 'err' : 'ok';
|
|
113
|
+
return Result.err(errors);
|
|
114
|
+
}
|
|
74
115
|
};
|
|
75
116
|
|
|
76
117
|
/**
|
|
77
118
|
* Format files matching the given glob pattern using Prettier
|
|
78
119
|
*
|
|
79
120
|
* @param pathGlob - Glob pattern to match files
|
|
80
|
-
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
81
121
|
*/
|
|
82
|
-
export const
|
|
122
|
+
export const formatFilesGlob = async (
|
|
83
123
|
pathGlob: string,
|
|
84
124
|
options?: Readonly<{ silent?: boolean }>,
|
|
85
|
-
): Promise<
|
|
125
|
+
): Promise<Result<undefined, unknown>> => {
|
|
86
126
|
const silent = options?.silent ?? false;
|
|
87
127
|
|
|
88
128
|
try {
|
|
@@ -97,13 +137,15 @@ export const formatFiles = async (
|
|
|
97
137
|
if (!silent) {
|
|
98
138
|
echo('No files found matching pattern:', pathGlob);
|
|
99
139
|
}
|
|
100
|
-
return
|
|
140
|
+
return Result.ok(undefined);
|
|
101
141
|
}
|
|
102
142
|
|
|
103
|
-
return await
|
|
143
|
+
return await formatFiles(files, { silent });
|
|
104
144
|
} catch (error) {
|
|
105
|
-
|
|
106
|
-
|
|
145
|
+
if (!silent) {
|
|
146
|
+
console.error('Error in formatFiles:', error);
|
|
147
|
+
}
|
|
148
|
+
return Result.err(error);
|
|
107
149
|
}
|
|
108
150
|
};
|
|
109
151
|
|
|
@@ -111,63 +153,72 @@ export const formatFiles = async (
|
|
|
111
153
|
* Format only files that have been changed (git status)
|
|
112
154
|
*
|
|
113
155
|
* @param options - Options for formatting
|
|
114
|
-
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
115
156
|
*/
|
|
116
|
-
export const
|
|
117
|
-
options?: Readonly<{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
157
|
+
export const formatUncommittedFiles = async (
|
|
158
|
+
options?: Readonly<{
|
|
159
|
+
untracked?: boolean;
|
|
160
|
+
modified?: boolean;
|
|
161
|
+
staged?: boolean;
|
|
162
|
+
silent?: boolean;
|
|
163
|
+
}>,
|
|
164
|
+
): Promise<
|
|
165
|
+
Result<
|
|
166
|
+
undefined,
|
|
167
|
+
ExecException | Readonly<{ message: string }> | readonly unknown[]
|
|
168
|
+
>
|
|
169
|
+
> => {
|
|
170
|
+
const {
|
|
171
|
+
untracked = true,
|
|
172
|
+
modified = true,
|
|
173
|
+
staged = true,
|
|
174
|
+
silent = false,
|
|
175
|
+
} = options ?? {};
|
|
176
|
+
|
|
177
|
+
const mut_files: string[] = [];
|
|
178
|
+
|
|
179
|
+
if (untracked) {
|
|
180
|
+
const untrackedFilesResult = await getUntrackedFiles({ silent });
|
|
125
181
|
|
|
126
182
|
if (Result.isErr(untrackedFilesResult)) {
|
|
127
|
-
|
|
128
|
-
|
|
183
|
+
if (!silent) {
|
|
184
|
+
console.error(
|
|
185
|
+
'Error getting changed files:',
|
|
186
|
+
untrackedFilesResult.value,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
return untrackedFilesResult;
|
|
129
190
|
}
|
|
130
191
|
|
|
131
|
-
|
|
192
|
+
mut_files.push(...untrackedFilesResult.value);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (modified) {
|
|
196
|
+
const diffFilesResult = await getModifiedFiles({ silent });
|
|
132
197
|
|
|
133
|
-
if (
|
|
198
|
+
if (Result.isErr(diffFilesResult)) {
|
|
134
199
|
if (!silent) {
|
|
135
|
-
|
|
200
|
+
console.error('Error getting changed files:', diffFilesResult.value);
|
|
136
201
|
}
|
|
137
|
-
return
|
|
202
|
+
return diffFilesResult;
|
|
138
203
|
}
|
|
139
204
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
205
|
+
mut_files.push(...diffFilesResult.value);
|
|
206
|
+
}
|
|
143
207
|
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
files.map(async (filePath) => {
|
|
147
|
-
try {
|
|
148
|
-
await fs.readFile(filePath, 'utf8');
|
|
149
|
-
return filePath;
|
|
150
|
-
} catch {
|
|
151
|
-
if (!silent) {
|
|
152
|
-
echo(`Skipping non-existent file: ${filePath}`);
|
|
153
|
-
}
|
|
154
|
-
return undefined;
|
|
155
|
-
}
|
|
156
|
-
}),
|
|
157
|
-
);
|
|
208
|
+
if (staged) {
|
|
209
|
+
const stagedFilesResult = await getStagedFiles({ silent });
|
|
158
210
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
211
|
+
if (Result.isErr(stagedFilesResult)) {
|
|
212
|
+
if (!silent) {
|
|
213
|
+
console.error('Error getting changed files:', stagedFilesResult.value);
|
|
214
|
+
}
|
|
215
|
+
return stagedFilesResult;
|
|
216
|
+
}
|
|
165
217
|
|
|
166
|
-
|
|
167
|
-
} catch (error) {
|
|
168
|
-
console.error('Error in formatUntracked:', error);
|
|
169
|
-
return 'err';
|
|
218
|
+
mut_files.push(...stagedFilesResult.value);
|
|
170
219
|
}
|
|
220
|
+
|
|
221
|
+
return formatFiles(Arr.uniq(mut_files), { silent });
|
|
171
222
|
};
|
|
172
223
|
|
|
173
224
|
/**
|
|
@@ -178,71 +229,103 @@ export const formatUntracked = async (
|
|
|
178
229
|
* @param options - Options for formatting
|
|
179
230
|
* @param options.includeUntracked - Include untracked files in addition to diff
|
|
180
231
|
* files (default is true)
|
|
232
|
+
* @param options.includeStaged - Include staged files in addition to diff files
|
|
233
|
+
* (default is true)
|
|
181
234
|
* @param options.silent - Silent mode to suppress command output (default is
|
|
182
235
|
* false)
|
|
183
|
-
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
184
236
|
*/
|
|
185
237
|
export const formatDiffFrom = async (
|
|
186
238
|
base: string,
|
|
187
|
-
options?: Readonly<{
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
239
|
+
options?: Readonly<{
|
|
240
|
+
includeUntracked?: boolean;
|
|
241
|
+
includeModified?: boolean;
|
|
242
|
+
includeStaged?: boolean;
|
|
243
|
+
silent?: boolean;
|
|
244
|
+
}>,
|
|
245
|
+
): Promise<
|
|
246
|
+
Result<
|
|
247
|
+
undefined,
|
|
248
|
+
| ExecException
|
|
249
|
+
| Readonly<{
|
|
250
|
+
message: string;
|
|
251
|
+
}>
|
|
252
|
+
| readonly unknown[]
|
|
253
|
+
>
|
|
254
|
+
> => {
|
|
255
|
+
// const silent = options?.silent ?? false;
|
|
256
|
+
const {
|
|
257
|
+
silent = false,
|
|
258
|
+
includeUntracked = true,
|
|
259
|
+
includeModified = true,
|
|
260
|
+
includeStaged = true,
|
|
261
|
+
} = options ?? {};
|
|
262
|
+
|
|
263
|
+
// Get files that differ from base branch/commit (excluding deleted files)
|
|
264
|
+
const diffFromBaseResult = await getDiffFrom(base, {
|
|
265
|
+
silent,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
if (Result.isErr(diffFromBaseResult)) {
|
|
269
|
+
if (!silent) {
|
|
198
270
|
console.error('Error getting changed files:', diffFromBaseResult.value);
|
|
199
|
-
return 'err';
|
|
200
271
|
}
|
|
272
|
+
return diffFromBaseResult;
|
|
273
|
+
}
|
|
201
274
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
275
|
+
const diffFiles = diffFromBaseResult.value;
|
|
276
|
+
const mut_allFiles: string[] = diffFiles.slice();
|
|
277
|
+
|
|
278
|
+
// If includeUntracked is true, also get untracked files
|
|
279
|
+
for (const { type, flag, fn } of [
|
|
280
|
+
{ type: 'untracked', flag: includeUntracked, fn: getUntrackedFiles },
|
|
281
|
+
{ type: 'modified', flag: includeModified, fn: getModifiedFiles },
|
|
282
|
+
{ type: 'staged', flag: includeStaged, fn: getStagedFiles },
|
|
283
|
+
]) {
|
|
284
|
+
if (flag) {
|
|
285
|
+
// eslint-disable-next-line no-await-in-loop
|
|
286
|
+
const filesResult = await fn({ silent });
|
|
287
|
+
|
|
288
|
+
if (Result.isErr(filesResult)) {
|
|
289
|
+
if (!silent) {
|
|
290
|
+
console.error(`Error getting ${type} files:`, filesResult.value);
|
|
291
|
+
}
|
|
292
|
+
return filesResult;
|
|
217
293
|
}
|
|
218
294
|
|
|
219
|
-
const
|
|
295
|
+
const files = filesResult.value;
|
|
220
296
|
|
|
221
297
|
// Combine and deduplicate files
|
|
222
|
-
mut_allFiles
|
|
223
|
-
|
|
224
|
-
if (!silent) {
|
|
225
|
-
echo(
|
|
226
|
-
`Formatting files that differ from ${base} and untracked files:`,
|
|
227
|
-
mut_allFiles,
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
} else {
|
|
231
|
-
if (!silent) {
|
|
232
|
-
echo(`Formatting files that differ from ${base}:`, mut_allFiles);
|
|
233
|
-
}
|
|
298
|
+
mut_allFiles.push(...files);
|
|
234
299
|
}
|
|
300
|
+
}
|
|
235
301
|
|
|
236
|
-
|
|
237
|
-
if (!silent) {
|
|
238
|
-
echo(`No files to format`);
|
|
239
|
-
}
|
|
240
|
-
return 'ok';
|
|
241
|
-
}
|
|
302
|
+
const allFiles = Arr.uniq(mut_allFiles);
|
|
242
303
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
304
|
+
if (!silent) {
|
|
305
|
+
const includedFileTypes = [
|
|
306
|
+
includeUntracked ? 'untracked files' : undefined,
|
|
307
|
+
includeModified ? 'modified files' : undefined,
|
|
308
|
+
includeStaged ? 'staged files' : undefined,
|
|
309
|
+
].filter(isNotUndefined);
|
|
310
|
+
|
|
311
|
+
const message = [
|
|
312
|
+
`Formatting files that differ from ${base}`,
|
|
313
|
+
includedFileTypes
|
|
314
|
+
.map((s, i) =>
|
|
315
|
+
i !== includedFileTypes.length - 1 ? `, ${s}` : ` and ${s}`,
|
|
316
|
+
)
|
|
317
|
+
.join(''),
|
|
318
|
+
].join('');
|
|
319
|
+
|
|
320
|
+
echo(`${message}:`, allFiles);
|
|
247
321
|
}
|
|
322
|
+
|
|
323
|
+
if (allFiles.length === 0) {
|
|
324
|
+
if (!silent) {
|
|
325
|
+
echo('No files to format');
|
|
326
|
+
}
|
|
327
|
+
return Result.ok(undefined);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return formatFiles(allFiles, { silent });
|
|
248
331
|
};
|