reslop 0.1.9 → 0.2.1
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 +25 -1
- package/README.md +3 -1
- package/bin/reslop.js +2 -2
- package/lib/ansi.js +148 -5
- package/lib/api.js +4 -2
- package/lib/capabilities.js +13 -14
- package/lib/cli.js +38 -49
- package/lib/clipboard.js +1 -1
- package/lib/{deps/changes.js → deps-diff.js} +309 -19
- package/lib/deps.js +498 -29
- package/lib/detect.js +1 -7
- package/lib/diff/align.js +7 -10
- package/lib/diff/diff.js +53 -0
- package/lib/diff/display.js +5 -4
- package/lib/diff/inline.js +26 -21
- package/lib/diff/items.js +6 -4
- package/lib/diff/patch.js +1 -3
- package/lib/diff/unit.js +392 -0
- package/lib/files.js +5 -8
- package/lib/{git/branches.js → git-branches.js} +191 -11
- package/lib/{git/dependencies.js → git-deps.js} +111 -38
- package/lib/git-reword-todo.js +20 -0
- package/lib/git.js +606 -68
- package/lib/github.js +28 -197
- package/lib/gitlab.js +24 -195
- package/lib/highlight/bash.js +1 -3
- package/lib/highlight/css.js +1 -3
- package/lib/highlight/js.js +11 -14
- package/lib/highlight.js +6 -9
- package/lib/keys.js +14 -8
- package/lib/manifest.js +330 -0
- package/lib/remote.js +374 -0
- package/lib/render/branches.js +18 -100
- package/lib/render/chrome.js +71 -14
- package/lib/render/commits.js +69 -60
- package/lib/render/diff.js +20 -20
- package/lib/render/files.js +6 -34
- package/lib/render/frame.js +36 -13
- package/lib/render/notes.js +26 -8
- package/lib/render/primitives.js +99 -11
- package/lib/{render.js → render/render.js} +8 -8
- package/lib/render/unit.js +41 -0
- package/lib/review-merge.js +270 -0
- package/lib/review.js +782 -14
- package/lib/select.js +5 -10
- package/lib/session/accessors.js +9 -1
- package/lib/session/actions.js +61 -18
- package/lib/session/branches.js +116 -128
- package/lib/session/change-actions.js +202 -123
- package/lib/session/commit.js +201 -115
- package/lib/session/compose.js +181 -15
- package/lib/session/dispatch.js +110 -60
- package/lib/session/files-pane.js +156 -148
- package/lib/session/items.js +22 -30
- package/lib/session/lifecycle.js +151 -54
- package/lib/session/load.js +19 -33
- package/lib/session/navigation.js +12 -1
- package/lib/session/ops.js +28 -41
- package/lib/session/pointer.js +57 -57
- package/lib/session/review.js +23 -37
- package/lib/session/terminal.js +6 -12
- package/lib/session/todos.js +37 -13
- package/lib/session/unit.js +208 -0
- package/lib/session/update.js +33 -46
- package/lib/session/view.js +78 -9
- package/lib/session/watch.js +128 -24
- package/lib/session.js +22 -246
- package/lib/source.js +3 -3
- package/lib/update.js +40 -75
- package/lib/{git/proc.js → utilities.js} +75 -11
- package/lib/wrap.js +1 -3
- package/package.json +2 -2
- package/lib/deps/items.js +0 -134
- package/lib/deps/manifest.js +0 -152
- package/lib/deps/merge.js +0 -120
- package/lib/deps/proposals.js +0 -164
- package/lib/deps/reports.js +0 -180
- package/lib/deps/rows.js +0 -176
- package/lib/deps/scan.js +0 -138
- package/lib/deps/usage.js +0 -68
- package/lib/deps/versions.js +0 -119
- package/lib/diff.js +0 -33
- package/lib/git/changes.js +0 -164
- package/lib/git/read.js +0 -253
- package/lib/git/run.js +0 -100
- package/lib/npm/commands.js +0 -100
- package/lib/remote/changes.js +0 -37
- package/lib/remote/headers.js +0 -36
- package/lib/remote/http.js +0 -122
- package/lib/remote/notes.js +0 -94
- package/lib/review/format.js +0 -434
- package/lib/review/storage.js +0 -150
- package/lib/review/store.js +0 -178
- package/lib/review/templates.js +0 -49
- package/lib/session/origins.js +0 -7
- package/lib/sys.js +0 -84
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const os = require('node:os');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
const { oneLine, requireOk, runGit, runGitAsync } = require('./git.js');
|
|
4
8
|
|
|
5
9
|
const BRANCH_FORMAT = [
|
|
6
10
|
'%(HEAD)',
|
|
@@ -20,12 +24,15 @@ const PUSH_REJECTED = [
|
|
|
20
24
|
'updates were rejected',
|
|
21
25
|
];
|
|
22
26
|
|
|
23
|
-
const
|
|
24
|
-
const
|
|
27
|
+
const commitMessage = (top, sha) => {
|
|
28
|
+
const spec = `${sha ?? ''}`.trim() || 'HEAD';
|
|
29
|
+
const result = runGit(['log', '-1', '--format=%B', spec], top);
|
|
25
30
|
if (result.status !== 0) return '';
|
|
26
31
|
return (result.stdout ?? '').replace(/\s+$/, '');
|
|
27
32
|
};
|
|
28
33
|
|
|
34
|
+
const lastMessage = (top) => commitMessage(top, 'HEAD');
|
|
35
|
+
|
|
29
36
|
const COMMIT_FORMAT = ['%H', '%h', '%an', '%ar', '%s'].join('%x1f');
|
|
30
37
|
const COMMIT_LIMIT = 256;
|
|
31
38
|
const UNIT = '\x1f';
|
|
@@ -120,6 +127,177 @@ const dropCommitAsync = async (top, sha) => {
|
|
|
120
127
|
await dropOlderCommitAsync(top, target);
|
|
121
128
|
};
|
|
122
129
|
|
|
130
|
+
const FIXUP_MARK = 'fixup!';
|
|
131
|
+
const AUTOSQUASH_ARGS = [
|
|
132
|
+
'-c',
|
|
133
|
+
'sequence.editor=:',
|
|
134
|
+
'rebase',
|
|
135
|
+
'--interactive',
|
|
136
|
+
'--autosquash',
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
const isFixupSubject = (subject) =>
|
|
140
|
+
`${subject ?? ''}`.trim().startsWith(FIXUP_MARK);
|
|
141
|
+
|
|
142
|
+
const fixupRest = (subject) => {
|
|
143
|
+
let text = `${subject ?? ''}`.trim();
|
|
144
|
+
while (text.startsWith(FIXUP_MARK)) {
|
|
145
|
+
text = text.slice(FIXUP_MARK.length).trim();
|
|
146
|
+
}
|
|
147
|
+
return text;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const commitSubject = (top, sha) => {
|
|
151
|
+
const args = ['log', '-1', '--format=%s', sha];
|
|
152
|
+
const result = requireOk(runGit(args, top), 'log failed');
|
|
153
|
+
return (result.stdout ?? '').trim();
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const ancestorWithSubject = (top, sha, want) => {
|
|
157
|
+
const args = ['log', `--format=${COMMIT_FORMAT}`, `${sha}^`];
|
|
158
|
+
const result = runGit(args, top);
|
|
159
|
+
if (result.status !== 0) return '';
|
|
160
|
+
for (const line of result.stdout.split('\n')) {
|
|
161
|
+
if (!line) continue;
|
|
162
|
+
const entry = parseCommitLine(line, 1);
|
|
163
|
+
if (entry && entry.subject === want) return entry.sha;
|
|
164
|
+
}
|
|
165
|
+
return '';
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const applyAutosquash = (top, ontoArgs) => {
|
|
169
|
+
const result = runGit([...AUTOSQUASH_ARGS, ...ontoArgs], top);
|
|
170
|
+
const failed = rebaseFailed(result);
|
|
171
|
+
if (!failed) return;
|
|
172
|
+
runGit(['rebase', '--abort'], top);
|
|
173
|
+
throw new Error(oneLine(failed));
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const applyAutosquashAsync = async (top, ontoArgs) => {
|
|
177
|
+
const result = await runGitAsync([...AUTOSQUASH_ARGS, ...ontoArgs], top);
|
|
178
|
+
const failed = rebaseFailed(result);
|
|
179
|
+
if (!failed) return;
|
|
180
|
+
await runGitAsync(['rebase', '--abort'], top);
|
|
181
|
+
throw new Error(oneLine(failed));
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const applyFixupOnto = (top, original, applyRange) => {
|
|
185
|
+
const parent = runGit(['rev-parse', '--verify', `${original}^`], top);
|
|
186
|
+
if (parent.status !== 0) return applyRange(top, ['--root']);
|
|
187
|
+
return applyRange(top, [(parent.stdout ?? '').trim()]);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const applyFixup = (top, sha) => {
|
|
191
|
+
const spec = namedCommit(sha);
|
|
192
|
+
const commit = resolveCommit(top, spec);
|
|
193
|
+
const subject = commitSubject(top, commit);
|
|
194
|
+
if (!isFixupSubject(subject)) throw new Error('not a fixup commit');
|
|
195
|
+
const want = fixupRest(subject);
|
|
196
|
+
if (!want) throw new Error('no fixup target');
|
|
197
|
+
const original = ancestorWithSubject(top, commit, want);
|
|
198
|
+
if (!original) throw new Error('no fixup target');
|
|
199
|
+
applyFixupOnto(top, original, applyAutosquash);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const applyFixupAsync = async (top, sha) => {
|
|
203
|
+
const spec = namedCommit(sha);
|
|
204
|
+
const commit = resolveCommit(top, spec);
|
|
205
|
+
const subject = commitSubject(top, commit);
|
|
206
|
+
if (!isFixupSubject(subject)) throw new Error('not a fixup commit');
|
|
207
|
+
const want = fixupRest(subject);
|
|
208
|
+
if (!want) throw new Error('no fixup target');
|
|
209
|
+
const original = ancestorWithSubject(top, commit, want);
|
|
210
|
+
if (!original) throw new Error('no fixup target');
|
|
211
|
+
await applyFixupOnto(top, original, applyAutosquashAsync);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const messageBody = (message) => {
|
|
215
|
+
const text = `${message ?? ''}`;
|
|
216
|
+
return text.endsWith('\n') ? text : `${text}\n`;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const rewordHead = (top, message) => {
|
|
220
|
+
const args = ['commit', '--amend', '--only', '-F', '-'];
|
|
221
|
+
requireOk(runGit(args, top, messageBody(message)));
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const REWORD_TODO = path.join(__dirname, 'git-reword-todo.js');
|
|
225
|
+
|
|
226
|
+
const prepareRewordEditor = (message) => {
|
|
227
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'reslop-reword-'));
|
|
228
|
+
const msgFile = path.join(dir, 'MSG');
|
|
229
|
+
fs.writeFileSync(msgFile, messageBody(message));
|
|
230
|
+
const node = JSON.stringify(process.execPath);
|
|
231
|
+
const script = JSON.stringify(REWORD_TODO);
|
|
232
|
+
return {
|
|
233
|
+
dir,
|
|
234
|
+
env: {
|
|
235
|
+
GIT_SEQUENCE_EDITOR: `${node} ${script}`,
|
|
236
|
+
RESLOP_REWORD_FILE: msgFile,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const rewordRange = (top, sha, env) => {
|
|
242
|
+
const parent = runGit(['rev-parse', '--verify', `${sha}^`], top);
|
|
243
|
+
const onto =
|
|
244
|
+
parent.status !== 0 ? ['--root'] : [(parent.stdout ?? '').trim()];
|
|
245
|
+
return runGit(['rebase', '--interactive', ...onto], top, undefined, { env });
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const rewordRangeAsync = async (top, sha, env) => {
|
|
249
|
+
const parent = runGit(['rev-parse', '--verify', `${sha}^`], top);
|
|
250
|
+
const onto =
|
|
251
|
+
parent.status !== 0 ? ['--root'] : [(parent.stdout ?? '').trim()];
|
|
252
|
+
return runGitAsync(['rebase', '--interactive', ...onto], top, { env });
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const finishRewordRebase = (top, result) => {
|
|
256
|
+
const failed = rebaseFailed(result);
|
|
257
|
+
if (!failed) return;
|
|
258
|
+
runGit(['rebase', '--abort'], top);
|
|
259
|
+
throw new Error(oneLine(failed));
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const rewordOlder = (top, sha, message) => {
|
|
263
|
+
const prepared = prepareRewordEditor(message);
|
|
264
|
+
try {
|
|
265
|
+
const result = rewordRange(top, sha, prepared.env);
|
|
266
|
+
finishRewordRebase(top, result);
|
|
267
|
+
} finally {
|
|
268
|
+
fs.rmSync(prepared.dir, { recursive: true, force: true });
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const rewordOlderAsync = async (top, sha, message) => {
|
|
273
|
+
const prepared = prepareRewordEditor(message);
|
|
274
|
+
try {
|
|
275
|
+
const result = await rewordRangeAsync(top, sha, prepared.env);
|
|
276
|
+
const failed = rebaseFailed(result);
|
|
277
|
+
if (!failed) return;
|
|
278
|
+
await runGitAsync(['rebase', '--abort'], top);
|
|
279
|
+
throw new Error(oneLine(failed));
|
|
280
|
+
} finally {
|
|
281
|
+
fs.rmSync(prepared.dir, { recursive: true, force: true });
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const rewordCommit = (top, sha, message) => {
|
|
286
|
+
const spec = namedCommit(sha);
|
|
287
|
+
const commit = resolveCommit(top, spec);
|
|
288
|
+
const head = resolveCommit(top, 'HEAD');
|
|
289
|
+
if (commit === head) return void rewordHead(top, message);
|
|
290
|
+
rewordOlder(top, commit, message);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const rewordCommitAsync = async (top, sha, message) => {
|
|
294
|
+
const spec = namedCommit(sha);
|
|
295
|
+
const commit = resolveCommit(top, spec);
|
|
296
|
+
const head = resolveCommit(top, 'HEAD');
|
|
297
|
+
if (commit === head) return void rewordHead(top, message);
|
|
298
|
+
await rewordOlderAsync(top, commit, message);
|
|
299
|
+
};
|
|
300
|
+
|
|
123
301
|
const parseTrack = (text) => {
|
|
124
302
|
const raw = `${text ?? ''}`.trim().replace(/^\[|\]$/g, '');
|
|
125
303
|
if (!raw) return { ahead: 0, behind: 0, gone: false };
|
|
@@ -183,10 +361,11 @@ const listBranches = (top) => {
|
|
|
183
361
|
const names = new Set();
|
|
184
362
|
for (const entry of branches) names.add(entry.name);
|
|
185
363
|
const primary = defaultBranch(top, names);
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
364
|
+
const { length } = branches;
|
|
365
|
+
const listed = new Array(length);
|
|
366
|
+
for (let i = 0; i < length; i++) {
|
|
367
|
+
const entry = branches[i];
|
|
368
|
+
listed[i] = { ...entry, isDefault: entry.name === primary };
|
|
190
369
|
}
|
|
191
370
|
return listed;
|
|
192
371
|
};
|
|
@@ -337,10 +516,6 @@ const hasStaged = (top) => {
|
|
|
337
516
|
};
|
|
338
517
|
|
|
339
518
|
const commitPlan = (kind, message) => {
|
|
340
|
-
if (kind === 'fixup') {
|
|
341
|
-
const target = (message ?? '').trim() || 'HEAD';
|
|
342
|
-
return { args: ['commit', `--fixup=${target}`], body: undefined };
|
|
343
|
-
}
|
|
344
519
|
const args = ['commit'];
|
|
345
520
|
if (kind === 'amend') args.push('--amend');
|
|
346
521
|
args.push('-F', '-');
|
|
@@ -361,6 +536,7 @@ const commitChangesAsync = async (top, kind, message) => {
|
|
|
361
536
|
|
|
362
537
|
module.exports = {
|
|
363
538
|
lastMessage,
|
|
539
|
+
commitMessage,
|
|
364
540
|
listCommits,
|
|
365
541
|
listBranches,
|
|
366
542
|
checkoutBranch,
|
|
@@ -371,6 +547,10 @@ module.exports = {
|
|
|
371
547
|
rebaseBranchAsync,
|
|
372
548
|
dropCommit,
|
|
373
549
|
dropCommitAsync,
|
|
550
|
+
applyFixup,
|
|
551
|
+
applyFixupAsync,
|
|
552
|
+
rewordCommit,
|
|
553
|
+
rewordCommitAsync,
|
|
374
554
|
dropBranch,
|
|
375
555
|
dropBranchAsync,
|
|
376
556
|
pullChanges,
|
|
@@ -3,21 +3,55 @@
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
|
|
6
|
-
const deps = require('
|
|
6
|
+
const deps = require('./deps.js');
|
|
7
7
|
const { foldDepItems, mergeDepFile, depFileMeta } = deps;
|
|
8
8
|
const { parseAuditReport, parseOutdatedReport } = deps;
|
|
9
9
|
const { mergeProposedItems, MANIFEST, LOCKFILE } = deps;
|
|
10
|
-
const
|
|
11
|
-
const {
|
|
12
|
-
const
|
|
13
|
-
const { abortError } =
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const { gitText, worktreeText, readDepSides } =
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
10
|
+
const { collectUsedNames, collectExportMeta } = deps;
|
|
11
|
+
const { itemPath, isPathInScope } = require('./files.js');
|
|
12
|
+
const proc = require('./utilities.js');
|
|
13
|
+
const { abortError, npmBin, npmOpts, runProc, runProcSync } = proc;
|
|
14
|
+
const git = require('./git.js');
|
|
15
|
+
const { oneLine, requireOk, runGit } = git;
|
|
16
|
+
const { gitText, worktreeText, readDepSides, revertOnePath } = git;
|
|
17
|
+
|
|
18
|
+
const AUDIT_MS = 15000;
|
|
19
|
+
const INSTALL_MS = 120000;
|
|
20
|
+
|
|
21
|
+
const npmProcOptions = (cwd, extra = {}) => ({
|
|
22
|
+
cwd,
|
|
23
|
+
encoding: proc.DEFAULT_ENCODING,
|
|
24
|
+
maxBuffer: proc.DEFAULT_MAX_BUFFER,
|
|
25
|
+
timeout: extra.timeout,
|
|
26
|
+
signal: extra.signal,
|
|
27
|
+
shell: npmOpts().shell,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const runNpm = (cwd, args) =>
|
|
31
|
+
runProcSync(npmBin(), args, npmProcOptions(cwd, { timeout: INSTALL_MS }));
|
|
32
|
+
|
|
33
|
+
const runNpmAsync = (cwd, args, extra = {}) =>
|
|
34
|
+
runProc(
|
|
35
|
+
npmBin(),
|
|
36
|
+
args,
|
|
37
|
+
npmProcOptions(cwd, { timeout: INSTALL_MS, signal: extra.signal }),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const runNpmJson = (top, args, timeout) => {
|
|
41
|
+
const result = runProcSync(npmBin(), args, npmProcOptions(top, { timeout }));
|
|
42
|
+
if (result.error) return '';
|
|
43
|
+
return result.stdout || '';
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const runNpmJsonAsync = async (top, args, timeout, signal) => {
|
|
47
|
+
const result = await runProc(
|
|
48
|
+
npmBin(),
|
|
49
|
+
args,
|
|
50
|
+
npmProcOptions(top, { timeout, signal }),
|
|
51
|
+
);
|
|
52
|
+
if (result.error) return '';
|
|
53
|
+
return result.stdout || '';
|
|
54
|
+
};
|
|
21
55
|
|
|
22
56
|
const depPaths = (item) => item.dep?.files ?? [];
|
|
23
57
|
|
|
@@ -25,15 +59,59 @@ const origDepItems = (item) => item.dep?.items ?? [];
|
|
|
25
59
|
|
|
26
60
|
const depChange = (item) => item.dep?.change ?? null;
|
|
27
61
|
|
|
62
|
+
const firstDepRel = (files, kind) => {
|
|
63
|
+
for (const rel of files) {
|
|
64
|
+
const meta = depFileMeta(rel);
|
|
65
|
+
if (meta && meta.kind === kind) return rel;
|
|
66
|
+
}
|
|
67
|
+
return '';
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const proposedNpmPlan = (top, item) => {
|
|
71
|
+
const change = depChange(item);
|
|
72
|
+
if (!change) return null;
|
|
73
|
+
const files = depPaths(item);
|
|
74
|
+
const lockOnly = change.section === 'resolved';
|
|
75
|
+
const removing = !!change.unused;
|
|
76
|
+
const manifest = firstDepRel(files, 'manifest');
|
|
77
|
+
const lockRel = firstDepRel(files, 'lockfile');
|
|
78
|
+
const picked = lockOnly ? lockRel : manifest;
|
|
79
|
+
const target = picked || files[0] || '';
|
|
80
|
+
const meta = depFileMeta(target);
|
|
81
|
+
if (!meta) return null;
|
|
82
|
+
const cwd = meta.dir === '.' ? top : path.join(top, meta.dir);
|
|
83
|
+
let npmArgs = ['i'];
|
|
84
|
+
if (removing) npmArgs = ['uninstall', change.name];
|
|
85
|
+
else if (lockOnly) npmArgs = ['audit', 'fix'];
|
|
86
|
+
const fail = removing ? 'npm uninstall failed' : 'npm i failed';
|
|
87
|
+
const dirLock = meta.dir === '.' ? LOCKFILE : `${meta.dir}/${LOCKFILE}`;
|
|
88
|
+
const lockPath = lockRel || dirLock;
|
|
89
|
+
const prepareManifest = !lockOnly && !removing && !!manifest;
|
|
90
|
+
return {
|
|
91
|
+
cwd,
|
|
92
|
+
npmArgs,
|
|
93
|
+
fail,
|
|
94
|
+
lockOnly,
|
|
95
|
+
lockPath,
|
|
96
|
+
manifest,
|
|
97
|
+
prepareManifest,
|
|
98
|
+
runner: item.dep.install,
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
|
|
28
102
|
const hasProposed = (item) => {
|
|
29
103
|
const change = depChange(item);
|
|
30
104
|
return !!(change && change.propose);
|
|
31
105
|
};
|
|
32
106
|
|
|
33
107
|
const relatedFiles = (items) => {
|
|
34
|
-
|
|
108
|
+
let size = 0;
|
|
109
|
+
for (const item of items) size += depPaths(item).length;
|
|
110
|
+
const files = new Array(size);
|
|
111
|
+
let i = 0;
|
|
35
112
|
for (const item of items) {
|
|
36
|
-
|
|
113
|
+
const paths = depPaths(item);
|
|
114
|
+
for (let j = 0; j < paths.length; j++) files[i++] = paths[j];
|
|
37
115
|
}
|
|
38
116
|
return files;
|
|
39
117
|
};
|
|
@@ -230,10 +308,7 @@ const captureFile = (top, rel) => {
|
|
|
230
308
|
|
|
231
309
|
const restoreFile = (top, saved) => {
|
|
232
310
|
const abs = path.join(top, saved.rel);
|
|
233
|
-
if (saved.existed)
|
|
234
|
-
fs.writeFileSync(abs, saved.text);
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
311
|
+
if (saved.existed) return void fs.writeFileSync(abs, saved.text);
|
|
237
312
|
try {
|
|
238
313
|
fs.unlinkSync(abs);
|
|
239
314
|
} catch {
|
|
@@ -242,8 +317,9 @@ const restoreFile = (top, saved) => {
|
|
|
242
317
|
};
|
|
243
318
|
|
|
244
319
|
const captureFiles = (top, rels) => {
|
|
245
|
-
const
|
|
246
|
-
|
|
320
|
+
const { length } = rels;
|
|
321
|
+
const owned = new Array(length);
|
|
322
|
+
for (let i = 0; i < length; i++) owned[i] = captureFile(top, rels[i]);
|
|
247
323
|
return owned;
|
|
248
324
|
};
|
|
249
325
|
|
|
@@ -299,9 +375,6 @@ const ownedRelsOf = (plan) => {
|
|
|
299
375
|
return rels;
|
|
300
376
|
};
|
|
301
377
|
|
|
302
|
-
const resultFailed = (result) =>
|
|
303
|
-
!!(result && (result.error || result.status !== 0));
|
|
304
|
-
|
|
305
378
|
const errorFromResult = (result, fail) => {
|
|
306
379
|
if (!result) return new Error(fail);
|
|
307
380
|
if (result.error) {
|
|
@@ -338,7 +411,9 @@ const stagePlan = (top, plan) => {
|
|
|
338
411
|
};
|
|
339
412
|
|
|
340
413
|
const finishPlan = (top, plan, result, stage) => {
|
|
341
|
-
if (
|
|
414
|
+
if (result && (result.error || result.status !== 0)) {
|
|
415
|
+
throw errorFromResult(result, plan.fail);
|
|
416
|
+
}
|
|
342
417
|
const stageFn = stage ?? stagePlan;
|
|
343
418
|
stageFn(top, plan);
|
|
344
419
|
};
|
|
@@ -409,10 +484,7 @@ const applyDepChange = (top, item, mode) => {
|
|
|
409
484
|
|
|
410
485
|
const addItem = (top, item) => {
|
|
411
486
|
if (item.origin === 'staged' || item.origin === 'commit') return;
|
|
412
|
-
if (depChange(item))
|
|
413
|
-
applyDepChange(top, item, 'add');
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
487
|
+
if (depChange(item)) return void applyDepChange(top, item, 'add');
|
|
416
488
|
const files = depPaths(item);
|
|
417
489
|
if (files.length) {
|
|
418
490
|
requireOk(runGit(['add', '--', ...files], top));
|
|
@@ -430,10 +502,7 @@ const addItemAsync = async (top, item) => {
|
|
|
430
502
|
|
|
431
503
|
const unstageItem = (top, item) => {
|
|
432
504
|
if (item.origin !== 'staged') return;
|
|
433
|
-
if (depChange(item))
|
|
434
|
-
applyDepChange(top, item, 'unstage');
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
505
|
+
if (depChange(item)) return void applyDepChange(top, item, 'unstage');
|
|
437
506
|
const files = depPaths(item);
|
|
438
507
|
if (files.length) {
|
|
439
508
|
requireOk(runGit(['restore', '--staged', '--', ...files], top));
|
|
@@ -441,10 +510,7 @@ const unstageItem = (top, item) => {
|
|
|
441
510
|
};
|
|
442
511
|
|
|
443
512
|
const revertDepItem = (top, item) => {
|
|
444
|
-
if (depChange(item))
|
|
445
|
-
applyDepChange(top, item, 'revert');
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
513
|
+
if (depChange(item)) return void applyDepChange(top, item, 'revert');
|
|
448
514
|
const byPath = new Map();
|
|
449
515
|
for (const orig of origDepItems(item)) {
|
|
450
516
|
const rel = itemPath(orig);
|
|
@@ -453,7 +519,7 @@ const revertDepItem = (top, item) => {
|
|
|
453
519
|
else byPath.set(rel, [orig]);
|
|
454
520
|
}
|
|
455
521
|
for (const rel of byPath.keys()) {
|
|
456
|
-
|
|
522
|
+
revertOnePath(top, rel, byPath.get(rel));
|
|
457
523
|
}
|
|
458
524
|
};
|
|
459
525
|
|
|
@@ -463,7 +529,7 @@ const revertFile = (top, rel, items) => {
|
|
|
463
529
|
for (const file of paths) {
|
|
464
530
|
const group = itemsForPath(file, items);
|
|
465
531
|
const targets = group.length ? group : items;
|
|
466
|
-
|
|
532
|
+
revertOnePath(top, file, targets);
|
|
467
533
|
}
|
|
468
534
|
};
|
|
469
535
|
|
|
@@ -486,4 +552,11 @@ module.exports = {
|
|
|
486
552
|
unstageItem,
|
|
487
553
|
revertDepItem,
|
|
488
554
|
revertFile,
|
|
555
|
+
AUDIT_MS,
|
|
556
|
+
INSTALL_MS,
|
|
557
|
+
runNpm,
|
|
558
|
+
runNpmAsync,
|
|
559
|
+
runNpmJson,
|
|
560
|
+
runNpmJsonAsync,
|
|
561
|
+
proposedNpmPlan,
|
|
489
562
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
|
|
5
|
+
const file = process.argv[process.argv.length - 1];
|
|
6
|
+
const msg = process.env.RESLOP_REWORD_FILE;
|
|
7
|
+
if (!file || !msg) process.exit(1);
|
|
8
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
9
|
+
const rows = text.split('\n');
|
|
10
|
+
const out = [];
|
|
11
|
+
let seen = false;
|
|
12
|
+
for (const row of rows) {
|
|
13
|
+
out.push(row);
|
|
14
|
+
if (seen) continue;
|
|
15
|
+
if (!/^(pick|p)\s+/.test(row)) continue;
|
|
16
|
+
const spec = JSON.stringify(msg);
|
|
17
|
+
out.push(`exec git commit --amend --only -F ${spec}`);
|
|
18
|
+
seen = true;
|
|
19
|
+
}
|
|
20
|
+
fs.writeFileSync(file, out.join('\n'));
|