reslop 0.2.6 → 0.3.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/CHANGELOG.md +27 -1
- package/README.md +16 -14
- package/bin/reslop.js +8 -5
- package/lib/agents/agents.js +504 -0
- package/lib/agents/allow.js +71 -0
- package/lib/agents/allow.json +16 -0
- package/lib/agents/models.js +460 -0
- package/lib/api.js +15 -12
- package/lib/cli.js +61 -66
- package/lib/{files.js → common/files.js} +51 -52
- package/lib/common/find.js +61 -0
- package/lib/common/format.js +101 -0
- package/lib/{utilities.js → common/process.js} +7 -95
- package/lib/common/tasks.json +27 -0
- package/lib/common/utilities.js +112 -0
- package/lib/dashboard/git.js +9 -16
- package/lib/dashboard/model.js +117 -51
- package/lib/dashboard/npm.js +133 -32
- package/lib/dashboard/tree.js +27 -30
- package/lib/{session → dashboard}/watch.js +41 -31
- package/lib/dashboard/workspace.js +151 -0
- package/lib/{deps.js → deps/deps.js} +31 -45
- package/lib/{deps-diff.js → deps/diff.js} +35 -25
- package/lib/{manifest.js → deps/manifest.js} +47 -30
- package/lib/diff/align.js +1 -2
- package/lib/diff/diff.js +2 -2
- package/lib/diff/display.js +29 -5
- package/lib/diff/inline.js +10 -14
- package/lib/diff/items.js +6 -4
- package/lib/diff/patch.js +39 -3
- package/lib/diff/unit.js +45 -16
- package/lib/{git-branches.js → git/branches.js} +53 -48
- package/lib/{git-deps.js → git/deps.js} +123 -95
- package/lib/git/git.js +71 -0
- package/lib/git/worktree.js +475 -0
- package/lib/highlight/bash.js +1 -2
- package/lib/highlight/csv.js +1 -2
- package/lib/highlight/dot.js +1 -2
- package/lib/{highlight.js → highlight/highlight.js} +42 -11
- package/lib/highlight/html.js +20 -18
- package/lib/highlight/json.js +1 -2
- package/lib/highlight/log.js +1 -2
- package/lib/highlight/txt.js +1 -2
- package/lib/{session → input}/actions.js +240 -71
- package/lib/{editor.js → input/editor.js} +7 -8
- package/lib/{keys.js → input/keys.js} +36 -39
- package/lib/input/line-edit.js +77 -0
- package/lib/input/menu-pick.js +70 -0
- package/lib/render/agents.js +640 -0
- package/lib/render/branches.js +4 -5
- package/lib/render/commits.js +54 -64
- package/lib/render/{dash-activity.js → dashboard/activity.js} +25 -40
- package/lib/render/dashboard/blocks.js +490 -0
- package/lib/render/{dashboard.js → dashboard/dashboard.js} +25 -22
- package/lib/render/diff.js +166 -45
- package/lib/render/field.js +131 -0
- package/lib/render/files.js +22 -8
- package/lib/render/footer.js +383 -0
- package/lib/render/frame.js +127 -25
- package/lib/render/header.js +176 -0
- package/lib/render/log.js +319 -0
- package/lib/render/menu.js +60 -0
- package/lib/render/notes.js +29 -13
- package/lib/render/npm.js +322 -196
- package/lib/render/packages.js +89 -0
- package/lib/render/primitives.js +109 -16
- package/lib/render/render.js +7 -11
- package/lib/render/repos.js +214 -0
- package/lib/render/status.js +370 -0
- package/lib/render/status.json +85 -0
- package/lib/render/{dash-table.js → table.js} +19 -61
- package/lib/render/tiles.js +203 -47
- package/lib/render/unit.js +32 -13
- package/lib/{report-model.js → report/model.js} +4 -6
- package/lib/{report-parse.js → report/parse.js} +9 -14
- package/lib/{report-render.js → report/render.js} +46 -14
- package/lib/{report-run.js → report/run.js} +42 -30
- package/lib/{report-test.js → report/test.js} +56 -55
- package/lib/{report-tools.js → report/tools.js} +24 -33
- package/lib/review/agent-instructions.md +9 -0
- package/lib/review/format.js +426 -0
- package/lib/{review-merge.js → review/merge.js} +9 -8
- package/lib/review/review.js +190 -0
- package/lib/review/store.js +281 -0
- package/lib/review/templates.js +83 -0
- package/lib/runs/commands.js +14 -0
- package/lib/runs/logs.js +299 -0
- package/lib/runs/output.js +174 -0
- package/lib/runs/process.js +113 -0
- package/lib/{runs.js → runs/runs.js} +84 -36
- package/lib/runs/scripts.js +150 -0
- package/lib/session/agents/agents.js +958 -0
- package/lib/session/agents/job.js +320 -0
- package/lib/session/agents/jobs.js +355 -0
- package/lib/session/agents/options.js +153 -0
- package/lib/session/agents/plans.js +83 -0
- package/lib/session/branches.js +36 -44
- package/lib/session/change-actions.js +34 -100
- package/lib/session/commit.js +122 -56
- package/lib/session/compose.js +197 -146
- package/lib/session/dashboard.js +183 -37
- package/lib/session/dispatch.js +120 -22
- package/lib/session/files-pane.js +60 -24
- package/lib/session/find.js +81 -0
- package/lib/session/import.js +82 -0
- package/lib/session/items.js +8 -17
- package/lib/session/lifecycle.js +96 -66
- package/lib/session/load.js +2 -4
- package/lib/session/navigation.js +8 -3
- package/lib/session/npm/history.js +249 -0
- package/lib/session/npm/npm.js +815 -0
- package/lib/session/npm/packages.js +150 -0
- package/lib/session/ops.js +125 -34
- package/lib/session/pointer.js +216 -10
- package/lib/session/prefs.js +112 -0
- package/lib/session/reads.js +109 -0
- package/lib/session/review.js +28 -10
- package/lib/session/run-panel.js +40 -0
- package/lib/{session.js → session/session.js} +166 -59
- package/lib/session/tasks.js +321 -66
- package/lib/session/templates.js +1 -1
- package/lib/session/terminal.js +94 -12
- package/lib/session/unit.js +35 -30
- package/lib/session/update.js +194 -6
- package/lib/session/view.js +72 -59
- package/lib/session/workspace.js +416 -0
- package/lib/{capabilities.js → source/capabilities.js} +3 -12
- package/lib/{github.js → source/github.js} +102 -32
- package/lib/{gitlab.js → source/gitlab.js} +87 -10
- package/lib/{remote.js → source/remote.js} +144 -40
- package/lib/source/review-threads.graphql +20 -0
- package/lib/source/source.js +74 -0
- package/lib/term/ansi.js +396 -0
- package/lib/{clipboard.js → term/clipboard.js} +3 -6
- package/lib/{select.js → term/select.js} +2 -2
- package/lib/term/themes/dark.json +122 -0
- package/lib/term/themes/light.json +122 -0
- package/lib/term/wide.txt +21 -0
- package/lib/{wrap.js → term/wrap.js} +4 -4
- package/package.json +2 -2
- package/lib/ansi.js +0 -505
- package/lib/detect.js +0 -34
- package/lib/diff/edit.js +0 -33
- package/lib/git-worktree.js +0 -437
- package/lib/git.js +0 -79
- package/lib/npm-commands.js +0 -522
- package/lib/render/chrome.js +0 -628
- package/lib/render/dash-blocks.js +0 -245
- package/lib/render/present.js +0 -19
- package/lib/render/report.js +0 -43
- package/lib/review.js +0 -744
- package/lib/session/accessors.js +0 -26
- package/lib/session/edit-click.js +0 -57
- package/lib/session/npm.js +0 -452
- package/lib/session/progress.js +0 -41
- package/lib/source.js +0 -36
- package/lib/update.js +0 -192
- /package/lib/{git-reword-todo.js → git/reword-todo.js} +0 -0
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const
|
|
6
|
-
const { itemPath } = files;
|
|
7
|
-
const patch = require('./diff/patch.js');
|
|
3
|
+
const { jsonParse } = require('metautil');
|
|
4
|
+
const { itemPath } = require('../common/files.js');
|
|
5
|
+
const patch = require('../diff/patch.js');
|
|
8
6
|
const { countSides, formatHunkHeader, formatPatch } = patch;
|
|
9
|
-
const
|
|
10
|
-
const { isCtxType } = diff;
|
|
7
|
+
const { isCtxType } = require('../diff/diff.js');
|
|
11
8
|
const manifest = require('./manifest.js');
|
|
12
9
|
const { MANIFEST, LOCKFILE, SECTION_KEYS, depFileMeta, relOf } = manifest;
|
|
13
10
|
const { listFilePath, readSections, emptySectionMaps } = manifest;
|
|
@@ -66,8 +63,10 @@ const lineEntryName = (text) => {
|
|
|
66
63
|
return entry ? entry[1] : '';
|
|
67
64
|
};
|
|
68
65
|
|
|
69
|
-
const lineInBlock = (item, line) =>
|
|
70
|
-
typeof item.blockId !== 'number'
|
|
66
|
+
const lineInBlock = (item, line) => {
|
|
67
|
+
const open = typeof item.blockId !== 'number';
|
|
68
|
+
return open || line.blockId === item.blockId;
|
|
69
|
+
};
|
|
71
70
|
|
|
72
71
|
const hunkOnlyFoldedDeps = (item, names) => {
|
|
73
72
|
if (!item.hunk || !names.size) return false;
|
|
@@ -86,8 +85,10 @@ const hunkOnlyFoldedDeps = (item, names) => {
|
|
|
86
85
|
|
|
87
86
|
const stripFoldedDepItem = (item, names) => {
|
|
88
87
|
if (!item.hunk || !names.size) return item;
|
|
89
|
-
const isFolded = (line) =>
|
|
90
|
-
line.type !== 'ctx'
|
|
88
|
+
const isFolded = (line) => {
|
|
89
|
+
const changed = line.type !== 'ctx';
|
|
90
|
+
return changed && names.has(lineEntryName(line.text));
|
|
91
|
+
};
|
|
91
92
|
const lines = item.hunk.lines.filter((line) => !isFolded(line));
|
|
92
93
|
if (lines.length === item.hunk.lines.length) return item;
|
|
93
94
|
const isEdit = (line) => line.type !== 'ctx' && lineInBlock(item, line);
|
|
@@ -164,8 +165,15 @@ const mergeResolved = (changes, oldResolved, newResolved, oldMaps, newMaps) => {
|
|
|
164
165
|
const action = changeAction(from, to);
|
|
165
166
|
const resolvedFrom = from;
|
|
166
167
|
const resolvedTo = to;
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
merged.push({
|
|
169
|
+
name,
|
|
170
|
+
section: 'resolved',
|
|
171
|
+
action,
|
|
172
|
+
from,
|
|
173
|
+
to,
|
|
174
|
+
resolvedFrom,
|
|
175
|
+
resolvedTo,
|
|
176
|
+
});
|
|
169
177
|
}
|
|
170
178
|
return merged;
|
|
171
179
|
};
|
|
@@ -194,29 +202,31 @@ const readJsonSides = (readSides, origin, rel) => {
|
|
|
194
202
|
|
|
195
203
|
const sectionMapsOf = (pkg, lock, manifestItems) => {
|
|
196
204
|
if (pkg.before || pkg.after) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
};
|
|
205
|
+
const oldMaps = readSections(pkg.before);
|
|
206
|
+
const newMaps = readSections(pkg.after);
|
|
207
|
+
return { oldMaps, newMaps };
|
|
201
208
|
}
|
|
202
209
|
if (manifestItems.length) return mapsFromHunks(manifestItems);
|
|
203
210
|
const oldMaps = lockRootSections(lock.before);
|
|
204
|
-
|
|
211
|
+
const newMaps = lockRootSections(lock.after);
|
|
212
|
+
return { oldMaps, newMaps };
|
|
205
213
|
};
|
|
206
214
|
|
|
207
215
|
const manifestPolicy = (manifestItems, pkg, hasChanges) => {
|
|
208
216
|
if (!manifestItems.length) {
|
|
209
|
-
|
|
217
|
+
const foldManifest = false;
|
|
218
|
+
const takeAllManifest = false;
|
|
219
|
+
return { foldManifest, takeAllManifest };
|
|
210
220
|
}
|
|
211
221
|
if (pkg.before || pkg.after) {
|
|
212
222
|
const onlyDeps = !hasFieldChanges(pkg.before, pkg.after);
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
};
|
|
223
|
+
const foldManifest = hasChanges;
|
|
224
|
+
const takeAllManifest = hasChanges && onlyDeps;
|
|
225
|
+
return { foldManifest, takeAllManifest };
|
|
217
226
|
}
|
|
218
|
-
const
|
|
219
|
-
|
|
227
|
+
const foldManifest = hasChanges && manifestItems.every(isDepOnlyItem);
|
|
228
|
+
const takeAllManifest = foldManifest;
|
|
229
|
+
return { foldManifest, takeAllManifest };
|
|
220
230
|
};
|
|
221
231
|
|
|
222
232
|
const summarizeGroup = (group, readSides) => {
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const MANIFEST = 'package.json';
|
|
10
|
-
const LOCKFILE = 'package-lock.json';
|
|
11
|
-
const DEP_KIND = { [MANIFEST]: 'manifest', [LOCKFILE]: 'lockfile' };
|
|
3
|
+
const { isHashObject, jsonParse } = require('metautil');
|
|
4
|
+
const { parseVersion, cmpVersion } = require('../common/utilities.js');
|
|
5
|
+
const files = require('../common/files.js');
|
|
6
|
+
const { MANIFEST, LOCKFILE, depFileMeta, relOf, listFilePath } = files;
|
|
7
|
+
|
|
12
8
|
const SECTION_KEYS = [
|
|
13
9
|
'dependencies',
|
|
14
10
|
'devDependencies',
|
|
@@ -19,23 +15,6 @@ const LOCK_PREFIX = 'node_modules/';
|
|
|
19
15
|
|
|
20
16
|
const isObject = (value) => !!value && typeof value === 'object';
|
|
21
17
|
|
|
22
|
-
const posixRel = (rel) => `${rel ?? ''}`.replaceAll('\\', '/');
|
|
23
|
-
|
|
24
|
-
const depFileMeta = (rel) => {
|
|
25
|
-
const normalized = posixRel(rel);
|
|
26
|
-
const kind = DEP_KIND[path.posix.basename(normalized)];
|
|
27
|
-
if (!normalized || !kind) return null;
|
|
28
|
-
return { kind, dir: path.posix.dirname(normalized) };
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const relOf = (dir, name) => (dir === '.' ? name : `${dir}/${name}`);
|
|
32
|
-
|
|
33
|
-
const listFilePath = (rel) => {
|
|
34
|
-
const meta = depFileMeta(rel);
|
|
35
|
-
if (meta && meta.kind === 'lockfile') return relOf(meta.dir, MANIFEST);
|
|
36
|
-
return posixRel(rel);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
18
|
const readSectionMap = (pkg, key) => {
|
|
40
19
|
const map = new Map();
|
|
41
20
|
const raw = pkg ? pkg[key] : null;
|
|
@@ -155,14 +134,17 @@ const seedManifest = (oldObj, newObj) => {
|
|
|
155
134
|
return base;
|
|
156
135
|
};
|
|
157
136
|
|
|
137
|
+
const mergedBase = (parsedBase, oldObj, newObj, kind) => {
|
|
138
|
+
if (parsedBase) return cloneJson(parsedBase);
|
|
139
|
+
if (kind === 'manifest') return seedManifest(oldObj, newObj);
|
|
140
|
+
return cloneJson(oldObj) || {};
|
|
141
|
+
};
|
|
142
|
+
|
|
158
143
|
const mergeDepFile = (baseText, oldText, newText, change, side, kind) => {
|
|
159
144
|
const oldObj = jsonParse(oldText ?? '');
|
|
160
145
|
const newObj = jsonParse(newText ?? '');
|
|
161
146
|
const parsedBase = jsonParse(baseText ?? '');
|
|
162
|
-
|
|
163
|
-
if (parsedBase) base = cloneJson(parsedBase);
|
|
164
|
-
else if (kind === 'manifest') base = seedManifest(oldObj, newObj);
|
|
165
|
-
else base = cloneJson(oldObj) || {};
|
|
147
|
+
const base = mergedBase(parsedBase, oldObj, newObj, kind);
|
|
166
148
|
if (kind === 'lockfile') applyLockChange(base, change, side, oldObj, newObj);
|
|
167
149
|
else applyManifestChange(base, change, side);
|
|
168
150
|
return stringifyJson(base, baseText || newText || oldText || '');
|
|
@@ -247,7 +229,42 @@ const proposedWanted = (out, vul) => {
|
|
|
247
229
|
return '';
|
|
248
230
|
};
|
|
249
231
|
|
|
232
|
+
const cmpText = (left, right) => {
|
|
233
|
+
const a = parseVersion(left);
|
|
234
|
+
const b = parseVersion(right);
|
|
235
|
+
if (!a || !b) return null;
|
|
236
|
+
return cmpVersion(a, b);
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const boundHolds = (cmp, op) => {
|
|
240
|
+
if (op === '<') return cmp < 0;
|
|
241
|
+
if (op === '<=') return cmp <= 0;
|
|
242
|
+
if (op === '>') return cmp > 0;
|
|
243
|
+
return cmp >= 0;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const inClause = (version, clause) => {
|
|
247
|
+
const ver = parseVersion(version);
|
|
248
|
+
if (!ver) return false;
|
|
249
|
+
const bounds = [...clause.matchAll(/(>=|<=|>|<)\s*(\d+\.\d+\.\d+)/g)];
|
|
250
|
+
if (!bounds.length) return false;
|
|
251
|
+
for (const match of bounds) {
|
|
252
|
+
const bound = parseVersion(match[2]);
|
|
253
|
+
if (!bound) return false;
|
|
254
|
+
if (!boundHolds(cmpVersion(ver, bound), match[1])) return false;
|
|
255
|
+
}
|
|
256
|
+
return true;
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const inRange = (version, range) =>
|
|
260
|
+
`${range ?? ''}`.split('||').some((clause) => inClause(version, clause));
|
|
261
|
+
|
|
262
|
+
const hasRange = (range) => /[<>]=?\s*\d+\.\d+\.\d+/.test(`${range ?? ''}`);
|
|
263
|
+
|
|
250
264
|
module.exports = {
|
|
265
|
+
cmpText,
|
|
266
|
+
inRange,
|
|
267
|
+
hasRange,
|
|
251
268
|
MANIFEST,
|
|
252
269
|
LOCKFILE,
|
|
253
270
|
SECTION_KEYS,
|
package/lib/diff/align.js
CHANGED
package/lib/diff/diff.js
CHANGED
|
@@ -5,7 +5,6 @@ const align = require('./align.js');
|
|
|
5
5
|
const parse = require('./parse.js');
|
|
6
6
|
const patch = require('./patch.js');
|
|
7
7
|
const display = require('./display.js');
|
|
8
|
-
const edit = require('./edit.js');
|
|
9
8
|
const items = require('./items.js');
|
|
10
9
|
const unit = require('./unit.js');
|
|
11
10
|
|
|
@@ -19,7 +18,8 @@ module.exports = {
|
|
|
19
18
|
flattenBlock: patch.flattenBlock,
|
|
20
19
|
formatPatch: patch.formatPatch,
|
|
21
20
|
...display,
|
|
22
|
-
|
|
21
|
+
addBlockRange: patch.addBlockRange,
|
|
22
|
+
replaceBlockAdds: patch.replaceBlockAdds,
|
|
23
23
|
...items,
|
|
24
24
|
...unit,
|
|
25
25
|
};
|
package/lib/diff/display.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const patch = require('./patch.js');
|
|
6
|
-
const { flattenBlock } = patch;
|
|
3
|
+
const { isCtxType, attachInline, LAYOUT_ALIGN } = require('./align.js');
|
|
4
|
+
const { flattenBlock } = require('./patch.js');
|
|
7
5
|
|
|
8
6
|
const DISPLAY_CONTEXT = 3;
|
|
9
7
|
|
|
@@ -80,11 +78,37 @@ const blockAddText = (hunk, blockId) => {
|
|
|
80
78
|
return parts.join('\n');
|
|
81
79
|
};
|
|
82
80
|
|
|
81
|
+
const countsOld = (line) => {
|
|
82
|
+
if (line.type === 'add' || line.synthetic === true) return false;
|
|
83
|
+
return line.type !== 'note' && line.type !== 'noteSep';
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const countsNew = (line) => line.type !== 'del';
|
|
87
|
+
|
|
88
|
+
const stampLineNumbers = (lines, hunk) => {
|
|
89
|
+
let oldNo = hunk && hunk.oldStart > 0 ? hunk.oldStart : 0;
|
|
90
|
+
let newNo = hunk && hunk.newStart > 0 ? hunk.newStart : 1;
|
|
91
|
+
return lines.map((line) => {
|
|
92
|
+
const next = { ...line };
|
|
93
|
+
if (line.type === 'note' || line.type === 'noteSep') return next;
|
|
94
|
+
if (countsOld(line)) {
|
|
95
|
+
if (oldNo > 0) next.oldNo = oldNo;
|
|
96
|
+
oldNo += 1;
|
|
97
|
+
}
|
|
98
|
+
if (countsNew(line)) {
|
|
99
|
+
next.newNo = newNo;
|
|
100
|
+
newNo += 1;
|
|
101
|
+
}
|
|
102
|
+
return next;
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
83
106
|
const displayLines = (hunk, blockId, layout = 'unified', radius, overlay) => {
|
|
84
107
|
const flat = flattenBlock(hunk, blockId, 'new');
|
|
85
108
|
const source = overlay ? replaceAdds(flat, overlay, blockId) : flat;
|
|
109
|
+
const numbered = stampLineNumbers(source, hunk);
|
|
86
110
|
const around = radius ?? DISPLAY_CONTEXT;
|
|
87
|
-
const painted = attachInline(windowAroundBlock(
|
|
111
|
+
const painted = attachInline(windowAroundBlock(numbered, blockId, around));
|
|
88
112
|
const alignRows = LAYOUT_ALIGN[layout];
|
|
89
113
|
return alignRows ? alignRows(painted) : painted;
|
|
90
114
|
};
|
package/lib/diff/inline.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const { graphemes } = ansi;
|
|
3
|
+
const { graphemes } = require('../term/ansi.js');
|
|
5
4
|
|
|
6
5
|
const LCS_CELL_LIMIT = 250000;
|
|
7
6
|
const NOISY_TINY_SPANS = 6;
|
|
@@ -131,10 +130,9 @@ const opsSpans = (ops) => {
|
|
|
131
130
|
newParts.push({ text: op.text, changed: op.type === 'add' });
|
|
132
131
|
}
|
|
133
132
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
};
|
|
133
|
+
const oldSpans = collapseSpans(oldParts);
|
|
134
|
+
const newSpans = collapseSpans(newParts);
|
|
135
|
+
return { oldSpans, newSpans };
|
|
138
136
|
};
|
|
139
137
|
|
|
140
138
|
const joinAffix = (prefix, mid, suffix) => {
|
|
@@ -154,10 +152,9 @@ const diffTrimmed = (a, b, spansOfOps) => {
|
|
|
154
152
|
const mid = whole ? wholeChanged(midA, midB) : spansOfOps(lcsOps(midA, midB));
|
|
155
153
|
const prefix = a.slice(0, lo);
|
|
156
154
|
const suffix = a.slice(hiA);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
};
|
|
155
|
+
const oldSpans = joinAffix(prefix, mid.oldSpans, suffix);
|
|
156
|
+
const newSpans = joinAffix(prefix, mid.newSpans, suffix);
|
|
157
|
+
return { oldSpans, newSpans };
|
|
161
158
|
};
|
|
162
159
|
|
|
163
160
|
const diffTokens = (a, b) => {
|
|
@@ -221,10 +218,9 @@ const refineWordOps = (ops) => {
|
|
|
221
218
|
if (dels.length) oldParts.push({ text: dels.join(''), changed: true });
|
|
222
219
|
if (adds.length) newParts.push({ text: adds.join(''), changed: true });
|
|
223
220
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
};
|
|
221
|
+
const oldSpans = collapseSpans(oldParts);
|
|
222
|
+
const newSpans = collapseSpans(newParts);
|
|
223
|
+
return { oldSpans, newSpans };
|
|
228
224
|
};
|
|
229
225
|
|
|
230
226
|
const opRuns = (ops) => {
|
package/lib/diff/items.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const { splitHunk, formatHunkHeader, formatPatch } = patch;
|
|
3
|
+
const { splitHunk, formatHunkHeader, formatPatch } = require('./patch.js');
|
|
5
4
|
|
|
6
5
|
const BINARY_ITEM = {
|
|
7
6
|
hunk: null,
|
|
@@ -70,8 +69,11 @@ const itemsFromFiles = (files, origin) => {
|
|
|
70
69
|
|
|
71
70
|
const refreshIndexPatches = (items, item) => {
|
|
72
71
|
if (!item.hunk) return items;
|
|
73
|
-
const isPeer = (other) =>
|
|
74
|
-
|
|
72
|
+
const isPeer = (other) => {
|
|
73
|
+
const sameHunk = other.hunk === item.hunk;
|
|
74
|
+
const sameFile = other.file === item.file;
|
|
75
|
+
return sameHunk && sameFile;
|
|
76
|
+
};
|
|
75
77
|
const peers = items.filter(isPeer);
|
|
76
78
|
const sides = {};
|
|
77
79
|
for (const peer of peers) sides[peer.blockId] = indexSide(peer.origin);
|
package/lib/diff/patch.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const { isCtxType } = align;
|
|
3
|
+
const { clamp } = require('../common/utilities.js');
|
|
4
|
+
const { isCtxType } = require('./align.js');
|
|
5
5
|
|
|
6
6
|
const LINE_MARK = { add: '+', del: '-' };
|
|
7
7
|
|
|
@@ -40,7 +40,11 @@ const flattenBlock = (hunk, blockId, contextSide) => {
|
|
|
40
40
|
}
|
|
41
41
|
const kept = sideOf(contextSide, line.blockId) === 'old' ? 'del' : 'add';
|
|
42
42
|
if (line.type === kept) {
|
|
43
|
-
|
|
43
|
+
const type = 'ctx';
|
|
44
|
+
const { text, noNl } = line;
|
|
45
|
+
const synthetic = true;
|
|
46
|
+
const row = { type, text, noNl, synthetic };
|
|
47
|
+
out.push(row);
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
return out;
|
|
@@ -72,10 +76,42 @@ const formatPatch = (file, hunk, blockId, contextSide) => {
|
|
|
72
76
|
return `${parts.join('\n')}\n`;
|
|
73
77
|
};
|
|
74
78
|
|
|
79
|
+
const addBlockRange = (hunk, blockId) => {
|
|
80
|
+
let newLine = hunk.newStart;
|
|
81
|
+
let start = 0;
|
|
82
|
+
let count = 0;
|
|
83
|
+
for (const line of hunk.lines) {
|
|
84
|
+
if (line.type === 'del') {
|
|
85
|
+
if (line.blockId === blockId && start === 0) start = newLine;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (line.type === 'add' && line.blockId === blockId) {
|
|
89
|
+
if (count === 0) start = newLine;
|
|
90
|
+
count += 1;
|
|
91
|
+
}
|
|
92
|
+
newLine += 1;
|
|
93
|
+
}
|
|
94
|
+
if (start === 0) start = hunk.newStart;
|
|
95
|
+
return { start, count };
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const replaceBlockAdds = (content, hunk, blockId, text) => {
|
|
99
|
+
const range = addBlockRange(hunk, blockId);
|
|
100
|
+
const ended = content.endsWith('\n');
|
|
101
|
+
const body = ended ? content.slice(0, -1) : content;
|
|
102
|
+
const lines = content === '' ? [] : body.split('\n');
|
|
103
|
+
const from = clamp(range.start - 1, 0, lines.length);
|
|
104
|
+
const added = text === '' ? [] : text.split('\n');
|
|
105
|
+
lines.splice(from, range.count, ...added);
|
|
106
|
+
return lines.join('\n') + (ended ? '\n' : '');
|
|
107
|
+
};
|
|
108
|
+
|
|
75
109
|
module.exports = {
|
|
76
110
|
splitHunk,
|
|
77
111
|
flattenBlock,
|
|
78
112
|
countSides,
|
|
79
113
|
formatHunkHeader,
|
|
80
114
|
formatPatch,
|
|
115
|
+
addBlockRange,
|
|
116
|
+
replaceBlockAdds,
|
|
81
117
|
};
|
package/lib/diff/unit.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const files = require('../files.js');
|
|
6
|
-
const { listPath } = files;
|
|
3
|
+
const { attachInline } = require('./align.js');
|
|
4
|
+
const { listPath } = require('../common/files.js');
|
|
7
5
|
|
|
8
6
|
const LCS_CELLS = 4000000;
|
|
9
7
|
|
|
@@ -75,6 +73,16 @@ const rowsFromAdds = (items) => {
|
|
|
75
73
|
return rows;
|
|
76
74
|
};
|
|
77
75
|
|
|
76
|
+
const stampFileNumbers = (lines) => {
|
|
77
|
+
let newNo = 1;
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
if (line.type === 'del') continue;
|
|
80
|
+
line.newNo = newNo;
|
|
81
|
+
newNo += 1;
|
|
82
|
+
}
|
|
83
|
+
return lines;
|
|
84
|
+
};
|
|
85
|
+
|
|
78
86
|
const unitLines = (text, items) => {
|
|
79
87
|
let rows = splitFile(text);
|
|
80
88
|
if (!rows.length) rows = rowsFromAdds(items);
|
|
@@ -95,11 +103,14 @@ const unitLines = (text, items) => {
|
|
|
95
103
|
out.push(tagged('del', del.text, del));
|
|
96
104
|
}
|
|
97
105
|
if (!out.length) out.push(tagged('ctx', '', NO_EXTRA));
|
|
98
|
-
return attachInline(out);
|
|
106
|
+
return stampFileNumbers(attachInline(out));
|
|
99
107
|
};
|
|
100
108
|
|
|
101
|
-
const sameBlock = (line, item) =>
|
|
102
|
-
|
|
109
|
+
const sameBlock = (line, item) => {
|
|
110
|
+
const sameItem = line.item === item;
|
|
111
|
+
const sameId = line.blockId === item.blockId;
|
|
112
|
+
return sameItem && sameId;
|
|
113
|
+
};
|
|
103
114
|
|
|
104
115
|
const changedLineRange = (lines, item, belongs) => {
|
|
105
116
|
let start = -1;
|
|
@@ -187,25 +198,33 @@ const zipOps = (prev, next) => {
|
|
|
187
198
|
};
|
|
188
199
|
|
|
189
200
|
const lcsOps = (prev, next) => {
|
|
190
|
-
const dp = lcsTable(prev, next);
|
|
191
201
|
const ops = [];
|
|
202
|
+
const limit = Math.min(prev.length, next.length);
|
|
203
|
+
let head = 0;
|
|
204
|
+
while (head < limit && prev[head] === next[head]) {
|
|
205
|
+
ops.push({ kind: 'eq', text: next[head] });
|
|
206
|
+
head += 1;
|
|
207
|
+
}
|
|
208
|
+
const left = head ? prev.slice(head) : prev;
|
|
209
|
+
const right = head ? next.slice(head) : next;
|
|
210
|
+
const dp = lcsTable(left, right);
|
|
192
211
|
let i = 0;
|
|
193
212
|
let j = 0;
|
|
194
|
-
while (i <
|
|
195
|
-
if (
|
|
196
|
-
ops.push({ kind: 'eq', text:
|
|
213
|
+
while (i < left.length && j < right.length) {
|
|
214
|
+
if (left[i] === right[j]) {
|
|
215
|
+
ops.push({ kind: 'eq', text: right[j] });
|
|
197
216
|
i += 1;
|
|
198
217
|
j += 1;
|
|
199
218
|
} else if (dp[i + 1][j] >= dp[i][j + 1]) {
|
|
200
219
|
ops.push({ kind: 'del' });
|
|
201
220
|
i += 1;
|
|
202
221
|
} else {
|
|
203
|
-
ops.push({ kind: 'ins', text:
|
|
222
|
+
ops.push({ kind: 'ins', text: right[j] });
|
|
204
223
|
j += 1;
|
|
205
224
|
}
|
|
206
225
|
}
|
|
207
|
-
for (; i <
|
|
208
|
-
for (; j <
|
|
226
|
+
for (; i < left.length; i++) ops.push({ kind: 'del' });
|
|
227
|
+
for (; j < right.length; j++) ops.push({ kind: 'ins', text: right[j] });
|
|
209
228
|
return ops;
|
|
210
229
|
};
|
|
211
230
|
|
|
@@ -241,7 +260,7 @@ const pushDels = (out, base, at) => {
|
|
|
241
260
|
return i;
|
|
242
261
|
};
|
|
243
262
|
|
|
244
|
-
const
|
|
263
|
+
const mergeRows = (base, nextTexts) => {
|
|
245
264
|
const texts = nextTexts.length ? nextTexts : [''];
|
|
246
265
|
const prev = [];
|
|
247
266
|
for (const row of base) if (row.type !== 'del') prev.push(row.text);
|
|
@@ -259,7 +278,17 @@ const mergeEditRows = (base, nextTexts) => {
|
|
|
259
278
|
}
|
|
260
279
|
pushDels(out, base, at);
|
|
261
280
|
if (!out.length) out.push(tagged('ctx', '', NO_EXTRA));
|
|
262
|
-
return attachEditSpans(attachInline(out));
|
|
281
|
+
return stampFileNumbers(attachEditSpans(attachInline(out)));
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
let merged = { base: null, text: '', rows: [] };
|
|
285
|
+
|
|
286
|
+
const mergeEditRows = (base, nextTexts) => {
|
|
287
|
+
const text = nextTexts.join('\n');
|
|
288
|
+
if (merged.base === base && merged.text === text) return merged.rows;
|
|
289
|
+
const rows = mergeRows(base, nextTexts);
|
|
290
|
+
merged = { base, text, rows };
|
|
291
|
+
return rows;
|
|
263
292
|
};
|
|
264
293
|
|
|
265
294
|
module.exports = {
|