reslop 0.2.5 → 0.2.6
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 +12 -1
- package/LICENSE +1 -1
- package/README.md +11 -11
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -8
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +39 -47
- package/lib/dashboard/git.js +128 -0
- package/lib/dashboard/model.js +332 -0
- package/lib/dashboard/npm.js +193 -0
- package/lib/dashboard/tree.js +278 -0
- package/lib/deps-diff.js +197 -402
- package/lib/deps.js +113 -240
- package/lib/detect.js +8 -18
- package/lib/diff/align.js +41 -113
- package/lib/diff/diff.js +12 -43
- package/lib/diff/display.js +25 -36
- package/lib/diff/edit.js +6 -20
- package/lib/diff/inline.js +76 -144
- package/lib/diff/items.js +33 -47
- package/lib/diff/parse.js +28 -56
- package/lib/diff/patch.js +12 -33
- package/lib/diff/unit.js +79 -178
- package/lib/editor.js +52 -69
- package/lib/files.js +71 -89
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +147 -272
- package/lib/git-reword-todo.js +5 -13
- package/lib/git-worktree.js +141 -212
- package/lib/git.js +21 -49
- package/lib/github.js +67 -181
- package/lib/gitlab.js +40 -90
- package/lib/highlight/bash.js +55 -177
- package/lib/highlight/core.js +155 -141
- package/lib/highlight/css.js +25 -58
- package/lib/highlight/csv.js +19 -37
- package/lib/highlight/dart.js +72 -213
- package/lib/highlight/dot.js +14 -14
- package/lib/highlight/html.js +42 -63
- package/lib/highlight/js.js +177 -506
- package/lib/highlight/json.js +17 -37
- package/lib/highlight/log.js +19 -25
- package/lib/highlight/txt.js +7 -10
- package/lib/highlight.js +17 -46
- package/lib/keys.js +49 -82
- package/lib/manifest.js +67 -126
- package/lib/npm-commands.js +120 -169
- package/lib/remote.js +140 -190
- package/lib/render/branches.js +63 -61
- package/lib/render/chrome.js +220 -333
- package/lib/render/commits.js +160 -361
- package/lib/render/dash-activity.js +212 -0
- package/lib/render/dash-blocks.js +245 -0
- package/lib/render/dash-table.js +290 -0
- package/lib/render/dashboard.js +62 -0
- package/lib/render/diff.js +123 -258
- package/lib/render/files.js +40 -85
- package/lib/render/frame.js +78 -117
- package/lib/render/notes.js +139 -210
- package/lib/render/npm.js +213 -177
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +72 -174
- package/lib/render/render.js +5 -14
- package/lib/render/report.js +43 -0
- package/lib/render/tiles.js +260 -0
- package/lib/render/unit.js +15 -31
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -37
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -77
- package/lib/report-test.js +221 -99
- package/lib/report-tools.js +96 -154
- package/lib/review-merge.js +33 -41
- package/lib/review.js +68 -129
- package/lib/runs.js +225 -0
- package/lib/select.js +53 -91
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +61 -43
- package/lib/session/branches.js +166 -222
- package/lib/session/change-actions.js +49 -119
- package/lib/session/commit.js +274 -355
- package/lib/session/compose.js +556 -714
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +162 -170
- package/lib/session/files-pane.js +76 -44
- package/lib/session/items.js +6 -17
- package/lib/session/lifecycle.js +393 -466
- package/lib/session/load.js +1 -14
- package/lib/session/navigation.js +2 -2
- package/lib/session/npm.js +403 -420
- package/lib/session/ops.js +5 -13
- package/lib/session/pointer.js +16 -14
- package/lib/session/progress.js +39 -30
- package/lib/session/review.js +1 -3
- package/lib/session/tasks.js +276 -235
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -132
- package/lib/session/view.js +47 -81
- package/lib/session/watch.js +196 -212
- package/lib/session.js +81 -161
- package/lib/update.js +44 -111
- package/lib/utilities.js +46 -88
- package/lib/wrap.js +29 -55
- package/package.json +1 -1
package/lib/git-deps.js
CHANGED
|
@@ -4,162 +4,121 @@ const fs = require('node:fs');
|
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
|
|
6
6
|
const deps = require('./deps.js');
|
|
7
|
-
const { foldDepItems,
|
|
7
|
+
const { foldDepItems, mergeProposedItems } = deps;
|
|
8
8
|
const { parseAuditReport, parseOutdatedReport } = deps;
|
|
9
|
-
const { mergeProposedItems, MANIFEST, LOCKFILE } = deps;
|
|
10
9
|
const { collectUsedNames, collectExportMeta } = deps;
|
|
10
|
+
const manifest = require('./manifest.js');
|
|
11
|
+
const { MANIFEST, LOCKFILE, depFileMeta, mergeDepFile, relOf } = manifest;
|
|
11
12
|
const files = require('./files.js');
|
|
12
13
|
const { itemPath, isPathInScope } = files;
|
|
13
|
-
const
|
|
14
|
-
const { abortError, npmBin,
|
|
15
|
-
const
|
|
16
|
-
const {
|
|
17
|
-
const {
|
|
18
|
-
const { writeFile, writeIndex } = git;
|
|
14
|
+
const utilities = require('./utilities.js');
|
|
15
|
+
const { IS_WIN, abortError, npmBin, oneLine, runProc, runProcSync } = utilities;
|
|
16
|
+
const worktree = require('./git-worktree.js');
|
|
17
|
+
const { requireOk, runGit, gitText, worktreeText, readDepSides } = worktree;
|
|
18
|
+
const { revertOnePath, groupByPath, writeFile, writeIndex } = worktree;
|
|
19
19
|
|
|
20
20
|
const AUDIT_MS = 15000;
|
|
21
21
|
const INSTALL_MS = 120000;
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const NPM_REPORT = {
|
|
24
|
+
audit: {
|
|
25
|
+
file: LOCKFILE,
|
|
26
|
+
args: ['audit', '--json', '--package-lock-only'],
|
|
27
|
+
parse: parseAuditReport,
|
|
28
|
+
},
|
|
29
|
+
outdated: {
|
|
30
|
+
file: MANIFEST,
|
|
31
|
+
args: ['outdated', '--json', '--long'],
|
|
32
|
+
parse: parseOutdatedReport,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const npmOptions = (cwd, timeout, signal) => ({
|
|
24
37
|
cwd,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
signal: extra.signal,
|
|
29
|
-
shell: npmOpts().shell,
|
|
38
|
+
timeout,
|
|
39
|
+
signal,
|
|
40
|
+
shell: IS_WIN,
|
|
30
41
|
});
|
|
31
42
|
|
|
32
43
|
const runNpm = (cwd, args) =>
|
|
33
|
-
runProcSync(npmBin(), args,
|
|
44
|
+
runProcSync(npmBin(), args, npmOptions(cwd, INSTALL_MS));
|
|
34
45
|
|
|
35
|
-
const runNpmAsync = (cwd, args
|
|
36
|
-
|
|
37
|
-
const signal = extra.signal;
|
|
38
|
-
const options = npmProcOptions(cwd, { timeout: INSTALL_MS, signal });
|
|
39
|
-
return runProc(bin, args, options);
|
|
40
|
-
};
|
|
46
|
+
const runNpmAsync = (cwd, args) =>
|
|
47
|
+
runProc(npmBin(), args, npmOptions(cwd, INSTALL_MS));
|
|
41
48
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
const npmOutput = (result) => (result.error ? '' : result.stdout);
|
|
50
|
+
|
|
51
|
+
const collectReport = (top, kind) => {
|
|
52
|
+
const report = NPM_REPORT[kind];
|
|
53
|
+
if (!fs.existsSync(path.join(top, report.file))) return null;
|
|
54
|
+
const options = npmOptions(top, AUDIT_MS);
|
|
55
|
+
return report.parse(npmOutput(runProcSync(npmBin(), report.args, options)));
|
|
46
56
|
};
|
|
47
57
|
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
);
|
|
54
|
-
if (result.error) return '';
|
|
55
|
-
return result.stdout || '';
|
|
58
|
+
const collectReportAsync = async (top, kind, signal) => {
|
|
59
|
+
const report = NPM_REPORT[kind];
|
|
60
|
+
if (!fs.existsSync(path.join(top, report.file))) return null;
|
|
61
|
+
const options = npmOptions(top, AUDIT_MS, signal);
|
|
62
|
+
const result = await runProc(npmBin(), report.args, options);
|
|
63
|
+
return report.parse(npmOutput(result));
|
|
56
64
|
};
|
|
57
65
|
|
|
58
66
|
const depPaths = (item) => item.dep?.files ?? [];
|
|
59
67
|
|
|
60
|
-
const origDepItems = (item) => item.dep?.items ?? [];
|
|
61
|
-
|
|
62
68
|
const depChange = (item) => item.dep?.change ?? null;
|
|
63
69
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
const hasProposed = (item) => !!depChange(item)?.propose;
|
|
71
|
+
|
|
72
|
+
const isStagedOrCommit = (item) =>
|
|
73
|
+
item.origin === 'staged' || item.origin === 'commit';
|
|
74
|
+
|
|
75
|
+
const firstDepRel = (rels, kind) =>
|
|
76
|
+
rels.find((rel) => depFileMeta(rel)?.kind === kind) ?? '';
|
|
71
77
|
|
|
72
78
|
const proposedNpmPlan = (top, item) => {
|
|
73
79
|
const change = depChange(item);
|
|
74
80
|
if (!change) return null;
|
|
75
|
-
const
|
|
81
|
+
const rels = depPaths(item);
|
|
76
82
|
const lockOnly = change.section === 'resolved';
|
|
77
83
|
const removing = !!change.unused;
|
|
78
|
-
const
|
|
79
|
-
const lockRel = firstDepRel(
|
|
80
|
-
const
|
|
81
|
-
const target = picked || files[0] || '';
|
|
82
|
-
const meta = depFileMeta(target);
|
|
84
|
+
const manifestRel = firstDepRel(rels, 'manifest');
|
|
85
|
+
const lockRel = firstDepRel(rels, 'lockfile');
|
|
86
|
+
const meta = depFileMeta((lockOnly ? lockRel : manifestRel) || rels[0]);
|
|
83
87
|
if (!meta) return null;
|
|
84
|
-
const cwd = meta.dir === '.' ? top : path.join(top, meta.dir);
|
|
85
88
|
let npmArgs = ['i'];
|
|
86
89
|
if (removing) npmArgs = ['uninstall', change.name];
|
|
87
90
|
else if (lockOnly) npmArgs = ['audit', 'fix'];
|
|
88
|
-
const fail = removing ? 'npm uninstall failed' : 'npm i failed';
|
|
89
|
-
const dirLock = meta.dir === '.' ? LOCKFILE : `${meta.dir}/${LOCKFILE}`;
|
|
90
|
-
const lockPath = lockRel || dirLock;
|
|
91
|
-
const prepareManifest = !lockOnly && !removing && !!manifest;
|
|
92
91
|
return {
|
|
93
|
-
cwd,
|
|
92
|
+
cwd: meta.dir === '.' ? top : path.join(top, meta.dir),
|
|
94
93
|
npmArgs,
|
|
95
|
-
fail,
|
|
94
|
+
fail: removing ? 'npm uninstall failed' : 'npm i failed',
|
|
96
95
|
lockOnly,
|
|
97
|
-
lockPath,
|
|
98
|
-
manifest,
|
|
99
|
-
prepareManifest,
|
|
96
|
+
lockPath: lockRel || relOf(meta.dir, LOCKFILE),
|
|
97
|
+
manifest: manifestRel,
|
|
98
|
+
prepareManifest: !lockOnly && !removing && !!manifestRel,
|
|
100
99
|
runner: item.dep.install,
|
|
101
100
|
};
|
|
102
101
|
};
|
|
103
102
|
|
|
104
|
-
const hasProposed = (item) => {
|
|
105
|
-
const change = depChange(item);
|
|
106
|
-
return !!(change && change.propose);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
103
|
const itemsForPath = (rel, items) => {
|
|
110
104
|
const group = [];
|
|
111
105
|
for (const item of items) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
continue;
|
|
106
|
+
const listed = item.dep ? item.dep.items : [item];
|
|
107
|
+
for (const entry of listed ?? []) {
|
|
108
|
+
if (itemPath(entry) === rel) group.push(entry);
|
|
117
109
|
}
|
|
118
|
-
if (itemPath(item) === rel) group.push(item);
|
|
119
110
|
}
|
|
120
111
|
return group;
|
|
121
112
|
};
|
|
122
113
|
|
|
123
|
-
const hasDepFile = (items) => {
|
|
124
|
-
for (const item of items) {
|
|
125
|
-
if (depFileMeta(itemPath(item))) return true;
|
|
126
|
-
}
|
|
127
|
-
return false;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const NPM_REPORT = {
|
|
131
|
-
audit: {
|
|
132
|
-
file: LOCKFILE,
|
|
133
|
-
args: ['audit', '--json', '--package-lock-only'],
|
|
134
|
-
parse: parseAuditReport,
|
|
135
|
-
},
|
|
136
|
-
outdated: {
|
|
137
|
-
file: MANIFEST,
|
|
138
|
-
args: ['outdated', '--json', '--long'],
|
|
139
|
-
parse: parseOutdatedReport,
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const collectReport = (top, kind) => {
|
|
144
|
-
const { file, args, parse } = NPM_REPORT[kind];
|
|
145
|
-
if (!fs.existsSync(path.join(top, file))) return null;
|
|
146
|
-
return parse(runNpmJson(top, args, AUDIT_MS));
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const collectReportAsync = async (top, kind, signal) => {
|
|
150
|
-
const { file, args, parse } = NPM_REPORT[kind];
|
|
151
|
-
if (!fs.existsSync(path.join(top, file))) return null;
|
|
152
|
-
return parse(await runNpmJsonAsync(top, args, AUDIT_MS, signal));
|
|
153
|
-
};
|
|
154
|
-
|
|
155
114
|
const extrasNeeds = (items, rev, extra) => {
|
|
156
115
|
const live = extra.audit === true && !rev;
|
|
157
|
-
const hasDepDiff =
|
|
116
|
+
const hasDepDiff = items.some((item) => depFileMeta(itemPath(item)));
|
|
158
117
|
const audit = live || (Boolean(extra.audit) && hasDepDiff);
|
|
159
118
|
return { live, scan: live || hasDepDiff, audit };
|
|
160
119
|
};
|
|
161
120
|
|
|
162
|
-
const foldLoaded = (items, top, rev, extra
|
|
121
|
+
const foldLoaded = (items, top, rev, extra) => {
|
|
163
122
|
const readSides = (origin, rel) => readDepSides(top, rev, origin, rel);
|
|
164
123
|
const needs = extrasNeeds(items, rev, extra);
|
|
165
124
|
const collect = extra.collect !== false;
|
|
@@ -181,25 +140,18 @@ const foldLoaded = (items, top, rev, extra = {}) => {
|
|
|
181
140
|
root: top,
|
|
182
141
|
exportEntries,
|
|
183
142
|
});
|
|
184
|
-
if (!needs.live) return folded;
|
|
185
|
-
if (!isPathInScope(MANIFEST, extra.paths ?? [])) return folded;
|
|
143
|
+
if (!needs.live || !isPathInScope(MANIFEST, extra.paths)) return folded;
|
|
186
144
|
const pkgText = worktreeText(top, MANIFEST);
|
|
187
145
|
const lockText = worktreeText(top, LOCKFILE);
|
|
188
146
|
const options = { lockText, usedNames, root: top, exportEntries };
|
|
189
147
|
return mergeProposedItems(folded, pkgText, outdated, audit, options);
|
|
190
148
|
};
|
|
191
149
|
|
|
192
|
-
const needsExtras = (parsed, rev, extra) =>
|
|
193
|
-
extrasNeeds(parsed, rev, extra).audit;
|
|
194
|
-
|
|
195
150
|
const finishLoad = (snapshot, extra) => {
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
const parsed = snapshot.parsed;
|
|
199
|
-
const top = snapshot.top;
|
|
200
|
-
const rev = snapshot.rev;
|
|
151
|
+
const { top, rev, parsed } = snapshot;
|
|
152
|
+
const options = { ...extra, collect: !extra.deferExtras };
|
|
201
153
|
const items = foldLoaded(parsed, top, rev, options);
|
|
202
|
-
const pending = extra.deferExtras &&
|
|
154
|
+
const pending = extra.deferExtras && extrasNeeds(parsed, rev, extra).audit;
|
|
203
155
|
return { ...snapshot, items, pending };
|
|
204
156
|
};
|
|
205
157
|
|
|
@@ -228,123 +180,56 @@ const loadExtras = async (snapshot, extra = {}) => {
|
|
|
228
180
|
: known,
|
|
229
181
|
]);
|
|
230
182
|
if (signal && signal.aborted) throw abortError();
|
|
231
|
-
const
|
|
183
|
+
const found = { usedNames, auditMap: audit, outdatedMap: outdated };
|
|
184
|
+
const items = foldLoaded(parsed, top, rev, {
|
|
232
185
|
...extra,
|
|
186
|
+
...found,
|
|
233
187
|
paths: extra.paths ?? [],
|
|
234
|
-
usedNames,
|
|
235
|
-
auditMap: audit,
|
|
236
|
-
outdatedMap: outdated,
|
|
237
188
|
exportEntries,
|
|
238
189
|
collect: false,
|
|
239
190
|
});
|
|
240
|
-
return {
|
|
241
|
-
...snapshot,
|
|
242
|
-
items: folded,
|
|
243
|
-
pending: false,
|
|
244
|
-
usedNames,
|
|
245
|
-
auditMap: audit,
|
|
246
|
-
outdatedMap: outdated,
|
|
247
|
-
exportEntries,
|
|
248
|
-
};
|
|
191
|
+
return { ...snapshot, items, pending: false, ...found, exportEntries };
|
|
249
192
|
};
|
|
250
193
|
|
|
251
194
|
const captureFile = (top, rel) => {
|
|
252
|
-
const abs = path.join(top, rel);
|
|
253
195
|
try {
|
|
254
|
-
const text = fs.readFileSync(
|
|
196
|
+
const text = fs.readFileSync(path.join(top, rel), 'utf8');
|
|
255
197
|
return { rel, existed: true, text };
|
|
256
198
|
} catch (error) {
|
|
257
|
-
if (error.code
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
throw error;
|
|
199
|
+
if (error.code !== 'ENOENT') throw error;
|
|
200
|
+
return { rel, existed: false, text: '' };
|
|
261
201
|
}
|
|
262
202
|
};
|
|
263
203
|
|
|
264
204
|
const restoreFile = (top, saved) => {
|
|
265
205
|
const abs = path.join(top, saved.rel);
|
|
266
|
-
if (saved.existed)
|
|
267
|
-
|
|
268
|
-
fs.unlinkSync(abs);
|
|
269
|
-
} catch {
|
|
270
|
-
// missing
|
|
271
|
-
}
|
|
206
|
+
if (saved.existed) fs.writeFileSync(abs, saved.text);
|
|
207
|
+
else fs.rmSync(abs, { force: true });
|
|
272
208
|
};
|
|
273
209
|
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
return owned;
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
const restoreFiles = (top, owned) => {
|
|
282
|
-
for (const saved of owned) restoreFile(top, saved);
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
const mergeDepLive = (top, rel, change, origin, base, side, kind) => {
|
|
286
|
-
const sides = readDepSides(top, null, origin, rel);
|
|
210
|
+
const mergeLive = (top, rel, item, base, side) => {
|
|
211
|
+
const sides = readDepSides(top, null, item.origin, rel);
|
|
212
|
+
const { kind } = depFileMeta(rel);
|
|
213
|
+
const change = depChange(item);
|
|
287
214
|
return mergeDepFile(base, sides.oldText, sides.newText, change, side, kind);
|
|
288
215
|
};
|
|
289
216
|
|
|
290
|
-
const applyDepIndex = (top, rel,
|
|
291
|
-
|
|
292
|
-
if (!meta) return;
|
|
217
|
+
const applyDepIndex = (top, rel, item, side) => {
|
|
218
|
+
if (!depFileMeta(rel)) return;
|
|
293
219
|
const indexed = gitText(top, `:${rel}`) || gitText(top, `HEAD:${rel}`);
|
|
294
|
-
|
|
295
|
-
writeIndex(top, rel, text);
|
|
220
|
+
writeIndex(top, rel, mergeLive(top, rel, item, indexed, side));
|
|
296
221
|
};
|
|
297
222
|
|
|
298
|
-
const applyDepWorktree = (top, rel,
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
const worktree = worktreeText(top, rel);
|
|
302
|
-
const text = mergeDepLive(
|
|
303
|
-
top,
|
|
304
|
-
rel,
|
|
305
|
-
change,
|
|
306
|
-
origin,
|
|
307
|
-
worktree,
|
|
308
|
-
'old',
|
|
309
|
-
meta.kind,
|
|
310
|
-
);
|
|
223
|
+
const applyDepWorktree = (top, rel, item, side) => {
|
|
224
|
+
if (!depFileMeta(rel)) return;
|
|
225
|
+
const text = mergeLive(top, rel, item, worktreeText(top, rel), side);
|
|
311
226
|
writeFile(top, rel, text);
|
|
312
227
|
};
|
|
313
228
|
|
|
314
|
-
const
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
rels.push(plan.lockPath);
|
|
319
|
-
}
|
|
320
|
-
return rels;
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const errorFromResult = (result, fail) => {
|
|
324
|
-
if (!result) return new Error(fail);
|
|
325
|
-
if (result.error) {
|
|
326
|
-
const msg = result.error.message || fail;
|
|
327
|
-
return new Error(oneLine(msg, fail));
|
|
328
|
-
}
|
|
329
|
-
const msg = result.stderr || result.stdout || fail;
|
|
330
|
-
return new Error(oneLine(msg, fail));
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
const applyPreparation = (top, item, plan) => {
|
|
334
|
-
if (!plan.prepareManifest || !plan.manifest) return;
|
|
335
|
-
const change = depChange(item);
|
|
336
|
-
const origin = item.origin;
|
|
337
|
-
const worktree = worktreeText(top, plan.manifest);
|
|
338
|
-
const text = mergeDepLive(
|
|
339
|
-
top,
|
|
340
|
-
plan.manifest,
|
|
341
|
-
change,
|
|
342
|
-
origin,
|
|
343
|
-
worktree,
|
|
344
|
-
'new',
|
|
345
|
-
'manifest',
|
|
346
|
-
);
|
|
347
|
-
writeFile(top, plan.manifest, text);
|
|
229
|
+
const npmError = (result, fail) => {
|
|
230
|
+
const { error } = result;
|
|
231
|
+
const msg = error ? error.message : result.stderr || result.stdout;
|
|
232
|
+
return new Error(oneLine(msg || fail, fail));
|
|
348
233
|
};
|
|
349
234
|
|
|
350
235
|
const stagePlan = (top, plan) => {
|
|
@@ -355,131 +240,121 @@ const stagePlan = (top, plan) => {
|
|
|
355
240
|
requireOk(runGit(['add', '--', ...toAdd], top));
|
|
356
241
|
};
|
|
357
242
|
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
const
|
|
363
|
-
|
|
243
|
+
const startPlan = (top, item) => {
|
|
244
|
+
const plan = proposedNpmPlan(top, item);
|
|
245
|
+
if (!plan) return null;
|
|
246
|
+
const rels = [...new Set([plan.manifest, plan.lockPath].filter(Boolean))];
|
|
247
|
+
const owned = rels.map((rel) => captureFile(top, rel));
|
|
248
|
+
return { plan, owned };
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const finishPlan = (top, plan, result, stage = stagePlan) => {
|
|
252
|
+
const failed = result && (result.error || result.status !== 0);
|
|
253
|
+
if (failed) throw npmError(result, plan.fail);
|
|
254
|
+
stage(top, plan);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const restoreOwned = (top, owned) => {
|
|
258
|
+
for (const saved of owned) restoreFile(top, saved);
|
|
364
259
|
};
|
|
365
260
|
|
|
366
261
|
const applyProposedUpdate = (top, item, extra = {}) => {
|
|
367
|
-
const
|
|
368
|
-
if (!
|
|
369
|
-
const owned =
|
|
262
|
+
const started = startPlan(top, item);
|
|
263
|
+
if (!started) return;
|
|
264
|
+
const { plan, owned } = started;
|
|
370
265
|
try {
|
|
371
|
-
|
|
266
|
+
if (plan.prepareManifest) applyDepWorktree(top, plan.manifest, item, 'new');
|
|
372
267
|
const install = extra.run ?? plan.runner ?? runNpm;
|
|
373
|
-
|
|
374
|
-
finishPlan(top, plan, result, extra.stage);
|
|
268
|
+
finishPlan(top, plan, install(plan.cwd, plan.npmArgs), extra.stage);
|
|
375
269
|
} catch (error) {
|
|
376
|
-
|
|
270
|
+
restoreOwned(top, owned);
|
|
377
271
|
throw error;
|
|
378
272
|
}
|
|
379
273
|
};
|
|
380
274
|
|
|
381
|
-
const applyProposedUpdateAsync = async (top, item
|
|
382
|
-
const
|
|
383
|
-
if (!
|
|
384
|
-
const owned =
|
|
275
|
+
const applyProposedUpdateAsync = async (top, item) => {
|
|
276
|
+
const started = startPlan(top, item);
|
|
277
|
+
if (!started) return;
|
|
278
|
+
const { plan, owned } = started;
|
|
385
279
|
try {
|
|
386
|
-
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
finishPlan(top, plan, result, extra.stage);
|
|
280
|
+
if (plan.prepareManifest) applyDepWorktree(top, plan.manifest, item, 'new');
|
|
281
|
+
const install = plan.runner ?? runNpmAsync;
|
|
282
|
+
finishPlan(top, plan, await install(plan.cwd, plan.npmArgs));
|
|
390
283
|
} catch (error) {
|
|
391
|
-
|
|
284
|
+
restoreOwned(top, owned);
|
|
392
285
|
throw error;
|
|
393
286
|
}
|
|
394
287
|
};
|
|
395
288
|
|
|
396
289
|
const applyDepChange = (top, item, mode) => {
|
|
397
290
|
const change = depChange(item);
|
|
398
|
-
if (change
|
|
291
|
+
if (change.propose) {
|
|
399
292
|
if (mode === 'add') return void applyProposedUpdate(top, item);
|
|
400
293
|
if (!change.unused) return;
|
|
401
294
|
}
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
if (mode === 'add') {
|
|
406
|
-
applyDepIndex(top, rel, change, origin, 'new');
|
|
295
|
+
for (const rel of depPaths(item)) {
|
|
296
|
+
if (mode !== 'revert') {
|
|
297
|
+
applyDepIndex(top, rel, item, mode === 'add' ? 'new' : 'old');
|
|
407
298
|
continue;
|
|
408
299
|
}
|
|
409
|
-
if (
|
|
410
|
-
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
413
|
-
if (origin === 'staged') applyDepIndex(top, rel, change, origin, 'old');
|
|
414
|
-
applyDepWorktree(top, rel, change, origin);
|
|
300
|
+
if (item.origin === 'staged') applyDepIndex(top, rel, item, 'old');
|
|
301
|
+
applyDepWorktree(top, rel, item, 'old');
|
|
415
302
|
}
|
|
416
303
|
};
|
|
417
304
|
|
|
418
305
|
const addItem = (top, item) => {
|
|
419
|
-
if (item.
|
|
306
|
+
if (!item.dep) return void worktree.addItem(top, item);
|
|
307
|
+
if (isStagedOrCommit(item)) return;
|
|
420
308
|
if (depChange(item)) return void applyDepChange(top, item, 'add');
|
|
421
|
-
const
|
|
422
|
-
if (
|
|
423
|
-
requireOk(runGit(['add', '--', ...files], top));
|
|
424
|
-
}
|
|
309
|
+
const rels = depPaths(item);
|
|
310
|
+
if (rels.length) requireOk(runGit(['add', '--', ...rels], top));
|
|
425
311
|
};
|
|
426
312
|
|
|
427
313
|
const addItemAsync = async (top, item) => {
|
|
428
|
-
if (item
|
|
429
|
-
|
|
430
|
-
await applyProposedUpdateAsync(top, item);
|
|
431
|
-
return;
|
|
314
|
+
if (isStagedOrCommit(item) || !hasProposed(item)) {
|
|
315
|
+
return void addItem(top, item);
|
|
432
316
|
}
|
|
433
|
-
|
|
317
|
+
await applyProposedUpdateAsync(top, item);
|
|
434
318
|
};
|
|
435
319
|
|
|
436
320
|
const unstageItem = (top, item) => {
|
|
321
|
+
if (!item.dep) return void worktree.unstageItem(top, item);
|
|
437
322
|
if (item.origin !== 'staged') return;
|
|
438
323
|
if (depChange(item)) return void applyDepChange(top, item, 'unstage');
|
|
439
|
-
const
|
|
440
|
-
if (
|
|
441
|
-
|
|
442
|
-
}
|
|
324
|
+
const rels = depPaths(item);
|
|
325
|
+
if (!rels.length) return;
|
|
326
|
+
requireOk(runGit(['restore', '--staged', '--', ...rels], top));
|
|
443
327
|
};
|
|
444
328
|
|
|
445
|
-
const
|
|
329
|
+
const revertItem = (top, item) => {
|
|
330
|
+
if (item.origin === 'commit') return;
|
|
331
|
+
if (!item.dep) return void worktree.revertItem(top, item);
|
|
446
332
|
if (depChange(item)) return void applyDepChange(top, item, 'revert');
|
|
447
|
-
const byPath =
|
|
448
|
-
for (const
|
|
449
|
-
const rel = itemPath(orig);
|
|
450
|
-
const list = byPath.get(rel);
|
|
451
|
-
if (list) list.push(orig);
|
|
452
|
-
else byPath.set(rel, [orig]);
|
|
453
|
-
}
|
|
454
|
-
for (const rel of byPath.keys()) {
|
|
455
|
-
revertOnePath(top, rel, byPath.get(rel));
|
|
456
|
-
}
|
|
333
|
+
const byPath = groupByPath(item.dep.items ?? []);
|
|
334
|
+
for (const rel of byPath.keys()) revertOnePath(top, rel, byPath.get(rel));
|
|
457
335
|
};
|
|
458
336
|
|
|
459
337
|
const revertFile = (top, rel, items) => {
|
|
460
|
-
const
|
|
338
|
+
const rels = new Set([rel]);
|
|
461
339
|
for (const item of items) {
|
|
462
|
-
for (const file of depPaths(item))
|
|
340
|
+
for (const file of depPaths(item)) rels.add(file);
|
|
463
341
|
}
|
|
464
|
-
for (const file of
|
|
342
|
+
for (const file of rels) {
|
|
465
343
|
const group = itemsForPath(file, items);
|
|
466
|
-
|
|
467
|
-
revertOnePath(top, file, targets);
|
|
344
|
+
revertOnePath(top, file, group.length ? group : items);
|
|
468
345
|
}
|
|
469
346
|
};
|
|
470
347
|
|
|
471
348
|
module.exports = {
|
|
472
|
-
itemsForPath,
|
|
473
349
|
finishLoad,
|
|
474
350
|
loadExtras,
|
|
475
351
|
captureFile,
|
|
476
352
|
restoreFile,
|
|
353
|
+
proposedNpmPlan,
|
|
477
354
|
applyProposedUpdate,
|
|
478
355
|
addItem,
|
|
479
356
|
addItemAsync,
|
|
480
357
|
unstageItem,
|
|
481
|
-
|
|
358
|
+
revertItem,
|
|
482
359
|
revertFile,
|
|
483
|
-
INSTALL_MS,
|
|
484
|
-
proposedNpmPlan,
|
|
485
360
|
};
|
package/lib/git-reword-todo.js
CHANGED
|
@@ -5,16 +5,8 @@ const fs = require('node:fs');
|
|
|
5
5
|
const file = process.argv[process.argv.length - 1];
|
|
6
6
|
const msg = process.env.RESLOP_REWORD_FILE;
|
|
7
7
|
if (!file || !msg) process.exit(1);
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
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'));
|
|
8
|
+
const rows = fs.readFileSync(file, 'utf8').split('\n');
|
|
9
|
+
const at = rows.findIndex((row) => /^(pick|p)\s+/.test(row));
|
|
10
|
+
const amend = `exec git commit --amend --only -F ${JSON.stringify(msg)}`;
|
|
11
|
+
if (at >= 0) rows.splice(at + 1, 0, amend);
|
|
12
|
+
fs.writeFileSync(file, rows.join('\n'));
|