reslop 0.1.2 → 0.1.4
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 -1
- package/README.md +38 -36
- package/lib/api.js +3 -0
- package/lib/cli.js +53 -16
- package/lib/clipboard.js +11 -11
- package/lib/detect.js +2 -0
- package/lib/files.js +36 -12
- package/lib/git.js +335 -65
- package/lib/gitlab.js +520 -0
- package/lib/highlight.js +160 -5
- package/lib/keys.js +8 -2
- package/lib/render.js +87 -30
- package/lib/session.js +227 -44
- package/lib/source.js +5 -2
- package/lib/sys.js +59 -0
- package/package.json +2 -2
package/lib/git.js
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { spawnSync } = require('node:child_process');
|
|
3
|
+
const { spawn, spawnSync } = require('node:child_process');
|
|
4
4
|
const fs = require('node:fs');
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
|
|
7
7
|
const diff = require('./diff.js');
|
|
8
8
|
const { parseDiff, synthesizeNewFile, itemsFromFiles } = diff;
|
|
9
9
|
const { itemPath, isPathInScope, REVIEW_DIR } = require('./files.js');
|
|
10
|
+
const { npmBin, spawnBase } = require('./sys.js');
|
|
10
11
|
const deps = require('./deps.js');
|
|
11
12
|
const { foldDepItems, mergeDepFile, depFileMeta } = deps;
|
|
12
13
|
const { collectUsedNames, parseAuditReport, parseOutdatedReport } = deps;
|
|
13
14
|
const { mergeProposedItems, MANIFEST, LOCKFILE } = deps;
|
|
14
15
|
|
|
15
|
-
const GIT_CONFIG = [
|
|
16
|
+
const GIT_CONFIG = [
|
|
17
|
+
'-c',
|
|
18
|
+
'core.quotepath=false',
|
|
19
|
+
'-c',
|
|
20
|
+
'i18n.logOutputEncoding=utf-8',
|
|
21
|
+
];
|
|
16
22
|
const DIFF_OPTS = ['--no-color', '--no-ext-diff', '--no-renames', '-U3'];
|
|
17
23
|
const GIT_ENCODING = 'utf8';
|
|
18
24
|
const GIT_MAX_BUFFER = 32 * 1024 * 1024;
|
|
@@ -46,17 +52,114 @@ const dropReviewItems = (items) => {
|
|
|
46
52
|
return kept;
|
|
47
53
|
};
|
|
48
54
|
|
|
55
|
+
const abortError = () => {
|
|
56
|
+
const error = new Error('aborted');
|
|
57
|
+
error.code = 'ABORT';
|
|
58
|
+
return error;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const isAbort = (error) => !!(error && error.code === 'ABORT');
|
|
62
|
+
|
|
63
|
+
const runProc = (cmd, args, options = {}) =>
|
|
64
|
+
new Promise((resolve) => {
|
|
65
|
+
const cwd = options.cwd;
|
|
66
|
+
const env = options.env;
|
|
67
|
+
const encoding = options.encoding ?? GIT_ENCODING;
|
|
68
|
+
const maxBuffer = options.maxBuffer ?? GIT_MAX_BUFFER;
|
|
69
|
+
const timeout = options.timeout;
|
|
70
|
+
const input = options.input;
|
|
71
|
+
const signal = options.signal;
|
|
72
|
+
if (signal && signal.aborted) {
|
|
73
|
+
resolve({ status: null, error: abortError(), stdout: '', stderr: '' });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let stdout = '';
|
|
77
|
+
let stderr = '';
|
|
78
|
+
let settled = false;
|
|
79
|
+
let timer = null;
|
|
80
|
+
const child = spawn(cmd, args, spawnBase({ cwd, env }));
|
|
81
|
+
const finish = (result) => {
|
|
82
|
+
if (settled) return;
|
|
83
|
+
settled = true;
|
|
84
|
+
if (timer) clearTimeout(timer);
|
|
85
|
+
resolve(result);
|
|
86
|
+
};
|
|
87
|
+
const onAbort = () => {
|
|
88
|
+
child.kill();
|
|
89
|
+
finish({ status: null, error: abortError(), stdout, stderr });
|
|
90
|
+
};
|
|
91
|
+
const append = (kind, chunk) => {
|
|
92
|
+
if (kind === 'out') stdout += chunk;
|
|
93
|
+
else stderr += chunk;
|
|
94
|
+
if (stdout.length + stderr.length <= maxBuffer) return;
|
|
95
|
+
child.kill();
|
|
96
|
+
const error = new Error('maxBuffer exceeded');
|
|
97
|
+
error.code = 'ENOBUFS';
|
|
98
|
+
finish({ status: null, error, stdout, stderr });
|
|
99
|
+
};
|
|
100
|
+
if (signal) signal.addEventListener('abort', onAbort);
|
|
101
|
+
if (child.stdout) {
|
|
102
|
+
child.stdout.setEncoding(encoding);
|
|
103
|
+
child.stdout.on('data', (chunk) => append('out', chunk));
|
|
104
|
+
}
|
|
105
|
+
if (child.stderr) {
|
|
106
|
+
child.stderr.setEncoding(encoding);
|
|
107
|
+
child.stderr.on('data', (chunk) => append('err', chunk));
|
|
108
|
+
}
|
|
109
|
+
if (timeout) {
|
|
110
|
+
timer = setTimeout(() => {
|
|
111
|
+
child.kill();
|
|
112
|
+
const error = new Error('timed out');
|
|
113
|
+
error.code = 'ETIMEDOUT';
|
|
114
|
+
finish({ status: null, error, stdout, stderr });
|
|
115
|
+
}, timeout);
|
|
116
|
+
}
|
|
117
|
+
child.on('error', (error) => {
|
|
118
|
+
finish({ status: null, error, stdout, stderr });
|
|
119
|
+
});
|
|
120
|
+
child.on('close', (status) => {
|
|
121
|
+
finish({ status, stdout, stderr });
|
|
122
|
+
});
|
|
123
|
+
if (child.stdin) {
|
|
124
|
+
try {
|
|
125
|
+
if (input) child.stdin.end(input);
|
|
126
|
+
else child.stdin.end();
|
|
127
|
+
} catch {
|
|
128
|
+
// closed
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const gitResult = (result) => {
|
|
134
|
+
if (!result.error) return result;
|
|
135
|
+
if (isAbort(result.error)) throw result.error;
|
|
136
|
+
if (result.error.code === 'ENOENT') throw new Error('git not found');
|
|
137
|
+
throw result.error;
|
|
138
|
+
};
|
|
139
|
+
|
|
49
140
|
const runGit = (args, cwd, input) => {
|
|
50
141
|
const env = { ...process.env, GIT_OPTIONAL_LOCKS: '0' };
|
|
51
142
|
const encoding = GIT_ENCODING;
|
|
52
143
|
const maxBuffer = GIT_MAX_BUFFER;
|
|
53
|
-
const options = { cwd, encoding, input, maxBuffer, env };
|
|
144
|
+
const options = spawnBase({ cwd, encoding, input, maxBuffer, env });
|
|
54
145
|
const result = spawnSync('git', args, options);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
146
|
+
return gitResult(result);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const runGitAsync = (args, cwd, extra = {}) => {
|
|
150
|
+
const env = { ...process.env, GIT_OPTIONAL_LOCKS: '0' };
|
|
151
|
+
const encoding = GIT_ENCODING;
|
|
152
|
+
const maxBuffer = GIT_MAX_BUFFER;
|
|
153
|
+
const input = extra.input;
|
|
154
|
+
const signal = extra.signal;
|
|
155
|
+
return runProc('git', args, {
|
|
156
|
+
cwd,
|
|
157
|
+
env,
|
|
158
|
+
encoding,
|
|
159
|
+
maxBuffer,
|
|
160
|
+
input,
|
|
161
|
+
signal,
|
|
162
|
+
}).then(gitResult);
|
|
60
163
|
};
|
|
61
164
|
|
|
62
165
|
const toplevel = (cwd) => {
|
|
@@ -76,12 +179,16 @@ const isBinaryBuffer = (buf) => {
|
|
|
76
179
|
return buf.includes(0);
|
|
77
180
|
};
|
|
78
181
|
|
|
182
|
+
const namesFromLs = (stdout) => {
|
|
183
|
+
if (!stdout) return [];
|
|
184
|
+
return stdout.split('\0').filter(Boolean);
|
|
185
|
+
};
|
|
186
|
+
|
|
79
187
|
const listUntracked = (top, paths) => {
|
|
80
188
|
const args = ['ls-files', '-o', '--exclude-standard', '-z'];
|
|
81
189
|
if (paths.length) args.push('--', ...paths);
|
|
82
190
|
const result = requireOk(runGit(args, top));
|
|
83
|
-
|
|
84
|
-
return result.stdout.split('\0').filter(Boolean);
|
|
191
|
+
return namesFromLs(result.stdout);
|
|
85
192
|
};
|
|
86
193
|
|
|
87
194
|
const binaryNewFile = (rel) => ({
|
|
@@ -94,9 +201,9 @@ const binaryNewFile = (rel) => ({
|
|
|
94
201
|
hunks: [],
|
|
95
202
|
});
|
|
96
203
|
|
|
97
|
-
const
|
|
204
|
+
const untrackedItemsFrom = (top, names) => {
|
|
98
205
|
const files = [];
|
|
99
|
-
for (const rel of
|
|
206
|
+
for (const rel of names) {
|
|
100
207
|
if (isReviewFile(rel)) continue;
|
|
101
208
|
const full = path.join(top, rel);
|
|
102
209
|
let buf;
|
|
@@ -174,11 +281,27 @@ const readDepSides = (top, rev, origin, rel) => {
|
|
|
174
281
|
};
|
|
175
282
|
|
|
176
283
|
const runNpmJson = (top, args, timeout) => {
|
|
177
|
-
const result = spawnSync(
|
|
284
|
+
const result = spawnSync(
|
|
285
|
+
npmBin(),
|
|
286
|
+
args,
|
|
287
|
+
spawnBase({
|
|
288
|
+
cwd: top,
|
|
289
|
+
encoding: GIT_ENCODING,
|
|
290
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
291
|
+
timeout,
|
|
292
|
+
}),
|
|
293
|
+
);
|
|
294
|
+
if (result.error) return '';
|
|
295
|
+
return result.stdout || '';
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const runNpmJsonAsync = async (top, args, timeout, signal) => {
|
|
299
|
+
const result = await runProc(npmBin(), args, {
|
|
178
300
|
cwd: top,
|
|
179
301
|
encoding: GIT_ENCODING,
|
|
180
302
|
maxBuffer: GIT_MAX_BUFFER,
|
|
181
303
|
timeout,
|
|
304
|
+
signal,
|
|
182
305
|
});
|
|
183
306
|
if (result.error) return '';
|
|
184
307
|
return result.stdout || '';
|
|
@@ -200,30 +323,55 @@ const collectOutdated = (top) => {
|
|
|
200
323
|
return parseOutdatedReport(text);
|
|
201
324
|
};
|
|
202
325
|
|
|
326
|
+
const collectAuditAsync = async (top, extra, signal) => {
|
|
327
|
+
if (extra.auditMap !== undefined) return extra.auditMap;
|
|
328
|
+
const lock = path.join(top, LOCKFILE);
|
|
329
|
+
if (!fs.existsSync(lock)) return null;
|
|
330
|
+
const args = ['audit', '--json', '--package-lock-only'];
|
|
331
|
+
const text = await runNpmJsonAsync(top, args, AUDIT_MS, signal);
|
|
332
|
+
return parseAuditReport(text);
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const collectOutdatedAsync = async (top, extra, signal) => {
|
|
336
|
+
if (extra.outdatedMap !== undefined) return extra.outdatedMap;
|
|
337
|
+
const manifest = path.join(top, MANIFEST);
|
|
338
|
+
if (!fs.existsSync(manifest)) return null;
|
|
339
|
+
const args = ['outdated', '--json', '--long'];
|
|
340
|
+
const text = await runNpmJsonAsync(top, args, AUDIT_MS, signal);
|
|
341
|
+
return parseOutdatedReport(text);
|
|
342
|
+
};
|
|
343
|
+
|
|
203
344
|
const pickNpmMap = (override, collect, top) => {
|
|
204
345
|
if (override !== undefined) return override;
|
|
205
346
|
return collect(top);
|
|
206
347
|
};
|
|
207
348
|
|
|
349
|
+
const hasDepFile = (items) => {
|
|
350
|
+
for (const item of items) {
|
|
351
|
+
if (depFileMeta(itemPath(item))) return true;
|
|
352
|
+
}
|
|
353
|
+
return false;
|
|
354
|
+
};
|
|
355
|
+
|
|
208
356
|
const foldLoaded = (items, top, rev, extra = {}) => {
|
|
209
357
|
const readSides = (origin, rel) => readDepSides(top, rev, origin, rel);
|
|
210
|
-
let usedNames = null;
|
|
211
|
-
let audit = null;
|
|
212
|
-
let outdated = null;
|
|
213
358
|
const live = extra.audit === true && !rev;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
359
|
+
const hasDepDiff = hasDepFile(items);
|
|
360
|
+
const collect = extra.collect !== false;
|
|
361
|
+
let usedNames = extra.usedNames ?? null;
|
|
362
|
+
let audit = extra.auditMap;
|
|
363
|
+
let outdated = extra.outdatedMap;
|
|
364
|
+
if (collect && usedNames === null && (hasDepDiff || live)) {
|
|
365
|
+
usedNames = collectUsedNames(top);
|
|
366
|
+
}
|
|
367
|
+
if (collect && live) {
|
|
222
368
|
audit = pickNpmMap(extra.auditMap, collectAudit, top);
|
|
223
369
|
outdated = pickNpmMap(extra.outdatedMap, collectOutdated, top);
|
|
224
|
-
} else if (extra.audit && hasDepDiff) {
|
|
370
|
+
} else if (collect && extra.audit && hasDepDiff) {
|
|
225
371
|
audit = pickNpmMap(extra.auditMap, collectAudit, top);
|
|
226
372
|
}
|
|
373
|
+
if (audit === undefined) audit = null;
|
|
374
|
+
if (outdated === undefined) outdated = null;
|
|
227
375
|
const folded = foldDepItems(items, readSides, usedNames, audit, outdated, {
|
|
228
376
|
root: top,
|
|
229
377
|
});
|
|
@@ -305,12 +453,16 @@ const applyDepWorktree = (top, rel, change, origin) => {
|
|
|
305
453
|
};
|
|
306
454
|
|
|
307
455
|
const runNpm = (cwd, args) =>
|
|
308
|
-
spawnSync(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
456
|
+
spawnSync(
|
|
457
|
+
npmBin(),
|
|
458
|
+
args,
|
|
459
|
+
spawnBase({
|
|
460
|
+
cwd,
|
|
461
|
+
encoding: GIT_ENCODING,
|
|
462
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
463
|
+
timeout: INSTALL_MS,
|
|
464
|
+
}),
|
|
465
|
+
);
|
|
314
466
|
|
|
315
467
|
const firstDepRel = (files, kind) => {
|
|
316
468
|
for (const rel of files) {
|
|
@@ -408,40 +560,73 @@ const shortRev = (top, commit) => {
|
|
|
408
560
|
return result.stdout.trim();
|
|
409
561
|
};
|
|
410
562
|
|
|
411
|
-
const
|
|
412
|
-
const parent = runGit(['rev-parse', '--verify', `${commit}^`], top);
|
|
413
|
-
let args;
|
|
563
|
+
const commitDiffArgs = (commit, parent, pathArgs) => {
|
|
414
564
|
if (parent.status === 0) {
|
|
415
565
|
const from = parent.stdout.trim();
|
|
416
|
-
|
|
417
|
-
} else {
|
|
418
|
-
args = [
|
|
419
|
-
...GIT_CONFIG,
|
|
420
|
-
'diff-tree',
|
|
421
|
-
'--no-commit-id',
|
|
422
|
-
'--root',
|
|
423
|
-
'-p',
|
|
424
|
-
...DIFF_OPTS,
|
|
425
|
-
commit,
|
|
426
|
-
...extra,
|
|
427
|
-
];
|
|
566
|
+
return [...GIT_CONFIG, 'diff', ...DIFF_OPTS, from, commit, ...pathArgs];
|
|
428
567
|
}
|
|
568
|
+
return [
|
|
569
|
+
...GIT_CONFIG,
|
|
570
|
+
'diff-tree',
|
|
571
|
+
'--no-commit-id',
|
|
572
|
+
'--root',
|
|
573
|
+
'-p',
|
|
574
|
+
...DIFF_OPTS,
|
|
575
|
+
commit,
|
|
576
|
+
...pathArgs,
|
|
577
|
+
];
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
const pathArgsOf = (paths) => (paths.length ? ['--', ...paths] : []);
|
|
581
|
+
|
|
582
|
+
const snapshotWorktree = (top, stagedOut, unstagedOut, names) => {
|
|
583
|
+
const stagedDiff = parseDiff(stagedOut);
|
|
584
|
+
const unstagedDiff = parseDiff(unstagedOut);
|
|
585
|
+
const staged = itemsFromFiles(stagedDiff, 'staged');
|
|
586
|
+
const unstaged = itemsFromFiles(unstagedDiff, 'unstaged');
|
|
587
|
+
const untracked = untrackedItemsFrom(top, names);
|
|
588
|
+
const combined = mergeItems([staged, unstaged, untracked]);
|
|
589
|
+
const parsed = dropReviewItems(combined);
|
|
590
|
+
return { top, parsed };
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
const snapshotCommit = (top, commit, files) => {
|
|
594
|
+
const commitItems = itemsFromFiles(files, 'commit');
|
|
595
|
+
const parsed = dropReviewItems(commitItems);
|
|
596
|
+
const revShort = shortRev(top, commit);
|
|
597
|
+
return { top, parsed, rev: commit, revShort };
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
const loadCommit = (top, commit, extra) => {
|
|
601
|
+
const parent = runGit(['rev-parse', '--verify', `${commit}^`], top);
|
|
602
|
+
const args = commitDiffArgs(commit, parent, extra);
|
|
429
603
|
const result = requireOk(runGit(args, top));
|
|
430
604
|
return parseDiff(result.stdout);
|
|
431
605
|
};
|
|
432
606
|
|
|
433
|
-
const
|
|
607
|
+
const needsExtras = (parsed, rev, extra) => {
|
|
608
|
+
const live = extra.audit === true && !rev;
|
|
609
|
+
if (live) return true;
|
|
610
|
+
if (!extra.audit) return false;
|
|
611
|
+
return hasDepFile(parsed);
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
const finishLoad = (snapshot, extra) => {
|
|
615
|
+
const options = { ...extra, paths: extra.paths ?? [] };
|
|
616
|
+
if (extra.deferExtras) options.collect = false;
|
|
617
|
+
const parsed = snapshot.parsed;
|
|
618
|
+
const top = snapshot.top;
|
|
619
|
+
const rev = snapshot.rev;
|
|
620
|
+
const items = foldLoaded(parsed, top, rev, options);
|
|
621
|
+
const pending = extra.deferExtras && needsExtras(parsed, rev, extra);
|
|
622
|
+
return { ...snapshot, items, pending };
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
const readSnapshotSync = (cwd, paths, options) => {
|
|
434
626
|
const top = toplevel(cwd);
|
|
435
|
-
const extra = paths
|
|
627
|
+
const extra = pathArgsOf(paths);
|
|
436
628
|
const rev = options.commit;
|
|
437
|
-
if (rev)
|
|
438
|
-
const files = loadCommit(top, rev, extra);
|
|
439
|
-
const commitItems = itemsFromFiles(files, 'commit');
|
|
440
|
-
const parsed = dropReviewItems(commitItems);
|
|
441
|
-
const items = foldLoaded(parsed, top, rev, { ...options, paths });
|
|
442
|
-
const revShort = shortRev(top, rev);
|
|
443
|
-
return { top, items, rev, revShort };
|
|
444
|
-
}
|
|
629
|
+
if (rev) return snapshotCommit(top, rev, loadCommit(top, rev, extra));
|
|
445
630
|
const stagedArgs = [
|
|
446
631
|
...GIT_CONFIG,
|
|
447
632
|
'diff',
|
|
@@ -452,15 +637,95 @@ const load = (cwd, paths = [], options = {}) => {
|
|
|
452
637
|
const unstagedArgs = [...GIT_CONFIG, 'diff', ...DIFF_OPTS, ...extra];
|
|
453
638
|
const stagedRes = requireOk(runGit(stagedArgs, top));
|
|
454
639
|
const unstagedRes = requireOk(runGit(unstagedArgs, top));
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
640
|
+
const names = listUntracked(top, paths);
|
|
641
|
+
return snapshotWorktree(top, stagedRes.stdout, unstagedRes.stdout, names);
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
const loadCommitAsync = async (top, commit, extra, signal) => {
|
|
645
|
+
const parent = await runGitAsync(
|
|
646
|
+
['rev-parse', '--verify', `${commit}^`],
|
|
647
|
+
top,
|
|
648
|
+
{ signal },
|
|
649
|
+
);
|
|
650
|
+
const args = commitDiffArgs(commit, parent, extra);
|
|
651
|
+
const result = requireOk(await runGitAsync(args, top, { signal }));
|
|
652
|
+
return parseDiff(result.stdout);
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
const readSnapshotAsync = async (cwd, paths, options) => {
|
|
656
|
+
const top = toplevel(cwd);
|
|
657
|
+
const extra = pathArgsOf(paths);
|
|
658
|
+
const rev = options.commit;
|
|
659
|
+
const signal = options.signal;
|
|
660
|
+
if (rev) {
|
|
661
|
+
const files = await loadCommitAsync(top, rev, extra, signal);
|
|
662
|
+
return snapshotCommit(top, rev, files);
|
|
663
|
+
}
|
|
664
|
+
const stagedArgs = [
|
|
665
|
+
...GIT_CONFIG,
|
|
666
|
+
'diff',
|
|
667
|
+
'--cached',
|
|
668
|
+
...DIFF_OPTS,
|
|
669
|
+
...extra,
|
|
670
|
+
];
|
|
671
|
+
const unstagedArgs = [...GIT_CONFIG, 'diff', ...DIFF_OPTS, ...extra];
|
|
672
|
+
const lsArgs = ['ls-files', '-o', '--exclude-standard', '-z'];
|
|
673
|
+
if (paths.length) lsArgs.push('--', ...paths);
|
|
674
|
+
const stagedP = runGitAsync(stagedArgs, top, { signal });
|
|
675
|
+
const unstagedP = runGitAsync(unstagedArgs, top, { signal });
|
|
676
|
+
const lsP = runGitAsync(lsArgs, top, { signal });
|
|
677
|
+
const stagedRes = requireOk(await stagedP);
|
|
678
|
+
const unstagedRes = requireOk(await unstagedP);
|
|
679
|
+
const names = namesFromLs(requireOk(await lsP).stdout);
|
|
680
|
+
return snapshotWorktree(top, stagedRes.stdout, unstagedRes.stdout, names);
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
const load = (cwd, paths = [], options = {}) => {
|
|
684
|
+
const snapshot = readSnapshotSync(cwd, paths, options);
|
|
685
|
+
return finishLoad(snapshot, { ...options, paths });
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
const loadAsync = async (cwd, paths = [], options = {}) => {
|
|
689
|
+
const snapshot = await readSnapshotAsync(cwd, paths, options);
|
|
690
|
+
return finishLoad(snapshot, { ...options, paths, deferExtras: true });
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
const usedNamesPromise = (parsed, rev, extra, top) => {
|
|
694
|
+
const live = extra.audit === true && !rev;
|
|
695
|
+
if (!live && !hasDepFile(parsed)) return Promise.resolve(null);
|
|
696
|
+
return Promise.resolve().then(() => collectUsedNames(top));
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
const loadExtras = async (snapshot, extra = {}) => {
|
|
700
|
+
const top = snapshot.top;
|
|
701
|
+
const rev = snapshot.rev;
|
|
702
|
+
const parsed = snapshot.parsed;
|
|
703
|
+
const signal = extra.signal;
|
|
704
|
+
const live = extra.audit === true && !rev;
|
|
705
|
+
const hasDepDiff = hasDepFile(parsed);
|
|
706
|
+
const usedP = usedNamesPromise(parsed, rev, extra, top);
|
|
707
|
+
let auditP = Promise.resolve(null);
|
|
708
|
+
let outdatedP = Promise.resolve(null);
|
|
709
|
+
if (live) {
|
|
710
|
+
auditP = collectAuditAsync(top, extra, signal);
|
|
711
|
+
outdatedP = collectOutdatedAsync(top, extra, signal);
|
|
712
|
+
} else if (extra.audit && hasDepDiff) {
|
|
713
|
+
auditP = collectAuditAsync(top, extra, signal);
|
|
714
|
+
}
|
|
715
|
+
const extras = await Promise.all([usedP, auditP, outdatedP]);
|
|
716
|
+
const usedNames = extras[0];
|
|
717
|
+
const audit = extras[1];
|
|
718
|
+
const outdated = extras[2];
|
|
719
|
+
if (signal && signal.aborted) throw abortError();
|
|
720
|
+
const folded = foldLoaded(parsed, top, rev, {
|
|
721
|
+
...extra,
|
|
722
|
+
paths: extra.paths ?? [],
|
|
723
|
+
usedNames,
|
|
724
|
+
auditMap: audit,
|
|
725
|
+
outdatedMap: outdated,
|
|
726
|
+
collect: false,
|
|
727
|
+
});
|
|
728
|
+
return { ...snapshot, items: folded, pending: false };
|
|
464
729
|
};
|
|
465
730
|
|
|
466
731
|
const addItem = (top, item) => {
|
|
@@ -594,6 +859,9 @@ const revertFile = (top, rel, items) => {
|
|
|
594
859
|
|
|
595
860
|
const createGitRepo = () => ({
|
|
596
861
|
load,
|
|
862
|
+
loadAsync,
|
|
863
|
+
loadExtras,
|
|
864
|
+
toplevel,
|
|
597
865
|
resolveRev,
|
|
598
866
|
add: addItem,
|
|
599
867
|
unstage: unstageItem,
|
|
@@ -603,6 +871,8 @@ const createGitRepo = () => ({
|
|
|
603
871
|
|
|
604
872
|
module.exports = {
|
|
605
873
|
load,
|
|
874
|
+
loadAsync,
|
|
875
|
+
loadExtras,
|
|
606
876
|
addItem,
|
|
607
877
|
unstageItem,
|
|
608
878
|
revertItem,
|