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,15 +1,75 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { spawn, spawnSync } = require('node:child_process');
|
|
4
|
+
const { split } = require('metautil');
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
-
|
|
6
|
+
const IS_WIN = process.platform === 'win32';
|
|
7
7
|
const DEFAULT_ENCODING = 'utf8';
|
|
8
8
|
const DEFAULT_MAX_BUFFER = 32 * 1024 * 1024;
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const UNIX_CLIP = [
|
|
11
|
+
{ cmd: 'wl-copy', args: [] },
|
|
12
|
+
{ cmd: 'xclip', args: ['-selection', 'clipboard'] },
|
|
13
|
+
{ cmd: 'xsel', args: ['--clipboard', '--input'] },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const parseVersion = (text) => {
|
|
17
|
+
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(`${text ?? ''}`);
|
|
18
|
+
if (!match) return null;
|
|
19
|
+
const [, major, minor, patch] = match.map(Number);
|
|
20
|
+
return { major, minor, patch };
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const cmpVersion = (left, right) =>
|
|
24
|
+
left.major - right.major ||
|
|
25
|
+
left.minor - right.minor ||
|
|
26
|
+
left.patch - right.patch;
|
|
27
|
+
|
|
28
|
+
const oneLine = (text, fallback = '') =>
|
|
29
|
+
split(`${text ?? ''}`.trim(), '\n')[0] || fallback;
|
|
30
|
+
|
|
31
|
+
const npmBin = (platform = process.platform) =>
|
|
32
|
+
platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
33
|
+
|
|
34
|
+
const spawnBase = (extra = {}) => ({ windowsHide: true, ...extra });
|
|
35
|
+
|
|
36
|
+
const npmOpts = (extra = {}, platform = process.platform) =>
|
|
37
|
+
spawnBase({ shell: platform === 'win32', ...extra });
|
|
38
|
+
|
|
39
|
+
const clipTools = (platform = process.platform) => {
|
|
40
|
+
if (platform === 'win32') return [{ cmd: 'clip', args: [] }];
|
|
41
|
+
if (platform === 'darwin') return [{ cmd: 'pbcopy', args: [] }];
|
|
42
|
+
return UNIX_CLIP;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const listen = (emitter, event, handler) => {
|
|
46
|
+
if (!emitter || typeof emitter.on !== 'function') return () => {};
|
|
47
|
+
emitter.on(event, handler);
|
|
48
|
+
return () => {
|
|
49
|
+
if (typeof emitter.removeListener === 'function') {
|
|
50
|
+
return void emitter.removeListener(event, handler);
|
|
51
|
+
}
|
|
52
|
+
if (typeof emitter.off === 'function') emitter.off(event, handler);
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const watchResize = (stdout, proc, onResize, signal) => {
|
|
57
|
+
const stopStdout = listen(stdout, 'resize', onResize);
|
|
58
|
+
let stopProc = () => {};
|
|
59
|
+
try {
|
|
60
|
+
stopProc = listen(proc, 'SIGWINCH', onResize);
|
|
61
|
+
} catch {
|
|
62
|
+
// SIGWINCH is not available on Windows
|
|
63
|
+
}
|
|
64
|
+
const stop = () => {
|
|
65
|
+
stopStdout();
|
|
66
|
+
stopProc();
|
|
67
|
+
};
|
|
68
|
+
if (signal) {
|
|
69
|
+
if (signal.aborted) stop();
|
|
70
|
+
else signal.addEventListener('abort', stop, { once: true });
|
|
71
|
+
}
|
|
72
|
+
return stop;
|
|
13
73
|
};
|
|
14
74
|
|
|
15
75
|
const abortError = () => {
|
|
@@ -51,12 +111,7 @@ const spawnOptions = (options = {}) => {
|
|
|
51
111
|
|
|
52
112
|
const runProcSync = (cmd, args, options = {}) => {
|
|
53
113
|
const result = spawnSync(cmd, args, spawnOptions(options));
|
|
54
|
-
return procResult(
|
|
55
|
-
status: result.status,
|
|
56
|
-
stdout: result.stdout,
|
|
57
|
-
stderr: result.stderr,
|
|
58
|
-
error: result.error,
|
|
59
|
-
});
|
|
114
|
+
return procResult(result);
|
|
60
115
|
};
|
|
61
116
|
|
|
62
117
|
const attachOutput = (stream, encoding, onChunk) => {
|
|
@@ -151,9 +206,18 @@ const runProc = (cmd, args, options = {}) =>
|
|
|
151
206
|
});
|
|
152
207
|
|
|
153
208
|
module.exports = {
|
|
209
|
+
IS_WIN,
|
|
154
210
|
DEFAULT_ENCODING,
|
|
155
211
|
DEFAULT_MAX_BUFFER,
|
|
212
|
+
parseVersion,
|
|
213
|
+
cmpVersion,
|
|
156
214
|
oneLine,
|
|
215
|
+
npmBin,
|
|
216
|
+
spawnBase,
|
|
217
|
+
npmOpts,
|
|
218
|
+
clipTools,
|
|
219
|
+
listen,
|
|
220
|
+
watchResize,
|
|
157
221
|
abortError,
|
|
158
222
|
isAbort,
|
|
159
223
|
procResult,
|
package/lib/wrap.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const { graphemes, graphemeWidth, visibleWidth } = require('./ansi.js');
|
|
4
4
|
|
|
5
|
-
const isWrapBreak = (ch) => ch === ' ' || ch === '\t';
|
|
6
|
-
|
|
7
5
|
const wrapPlain = (text, width) => {
|
|
8
6
|
if (width <= 0) return [''];
|
|
9
7
|
if (visibleWidth(text) <= width) return [text];
|
|
@@ -36,7 +34,7 @@ const wrapPlain = (text, width) => {
|
|
|
36
34
|
continue;
|
|
37
35
|
}
|
|
38
36
|
col += w;
|
|
39
|
-
if (
|
|
37
|
+
if (ch === ' ' || ch === '\t') lastBreak = i;
|
|
40
38
|
i += 1;
|
|
41
39
|
}
|
|
42
40
|
rows.push(slice(start, parts.length));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reslop",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Interactive code review and repair planning for AI-assisted changes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"code-review",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"eslint": "^9.39.4",
|
|
60
60
|
"eslint-config-metarhia": "^9.1.9",
|
|
61
61
|
"metaskills": "^1.0.5",
|
|
62
|
-
"prettier": "^3.9.
|
|
62
|
+
"prettier": "^3.9.9"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"metautil": "^5.5.2"
|
package/lib/deps/items.js
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { itemPath } = require('../files.js');
|
|
4
|
-
|
|
5
|
-
const { depFileMeta, listFilePath } = require('./manifest.js');
|
|
6
|
-
const { orderedChanges } = require('./changes.js');
|
|
7
|
-
const { buildRows, makeHunk } = require('./rows.js');
|
|
8
|
-
|
|
9
|
-
const uniquePaths = (items) => {
|
|
10
|
-
const files = [];
|
|
11
|
-
const seen = new Set();
|
|
12
|
-
for (const item of items) {
|
|
13
|
-
const rel = itemPath(item);
|
|
14
|
-
if (!rel || seen.has(rel)) continue;
|
|
15
|
-
seen.add(rel);
|
|
16
|
-
files.push(rel);
|
|
17
|
-
}
|
|
18
|
-
return files;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const filesForChange = (change, files) => {
|
|
22
|
-
const manifest = [];
|
|
23
|
-
const lockfile = [];
|
|
24
|
-
for (const rel of files) {
|
|
25
|
-
const meta = depFileMeta(rel);
|
|
26
|
-
if (!meta) continue;
|
|
27
|
-
if (meta.kind === 'manifest') manifest.push(rel);
|
|
28
|
-
else lockfile.push(rel);
|
|
29
|
-
}
|
|
30
|
-
if (change.section === 'field') {
|
|
31
|
-
if (manifest.length) return manifest;
|
|
32
|
-
return files;
|
|
33
|
-
}
|
|
34
|
-
if (change.section === 'resolved') {
|
|
35
|
-
if (lockfile.length) return lockfile;
|
|
36
|
-
return files;
|
|
37
|
-
}
|
|
38
|
-
if (change.propose) {
|
|
39
|
-
if (manifest.length) return manifest;
|
|
40
|
-
return files;
|
|
41
|
-
}
|
|
42
|
-
const both = [...manifest, ...lockfile];
|
|
43
|
-
if (both.length) return both;
|
|
44
|
-
return files;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const pickPrimary = (items) => {
|
|
48
|
-
for (const item of items) {
|
|
49
|
-
const rel = itemPath(item);
|
|
50
|
-
const meta = depFileMeta(rel);
|
|
51
|
-
if (meta && meta.kind === 'manifest') return item;
|
|
52
|
-
}
|
|
53
|
-
return items[0];
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const makeDepItem = (origin, fileItems, hidden, change, extra, blockId) => {
|
|
57
|
-
const allFiles = uniquePaths(fileItems);
|
|
58
|
-
const files = change ? filesForChange(change, allFiles) : allFiles;
|
|
59
|
-
const primary = pickPrimary(fileItems);
|
|
60
|
-
const oldPath = listFilePath(itemPath(primary));
|
|
61
|
-
const newPath = oldPath;
|
|
62
|
-
const isNew = fileItems.some((item) => item.file && item.file.isNew);
|
|
63
|
-
const isDeleted = fileItems.every((item) => item.file && item.file.isDeleted);
|
|
64
|
-
let oldCount = 0;
|
|
65
|
-
let newCount = 0;
|
|
66
|
-
if (!change) {
|
|
67
|
-
oldCount = extra.oldCount ?? 0;
|
|
68
|
-
newCount = extra.newCount ?? 0;
|
|
69
|
-
}
|
|
70
|
-
const rows = buildRows(change, oldCount, newCount);
|
|
71
|
-
const hunk = makeHunk(rows, blockId);
|
|
72
|
-
const isBinary = false;
|
|
73
|
-
const preamble = [];
|
|
74
|
-
const hunks = [hunk];
|
|
75
|
-
const file = {
|
|
76
|
-
oldPath,
|
|
77
|
-
newPath,
|
|
78
|
-
isNew,
|
|
79
|
-
isDeleted,
|
|
80
|
-
isBinary,
|
|
81
|
-
preamble,
|
|
82
|
-
hunks,
|
|
83
|
-
};
|
|
84
|
-
const patchAdd = '';
|
|
85
|
-
const patchRevert = '';
|
|
86
|
-
const items = hidden;
|
|
87
|
-
const dep = { files, items, change };
|
|
88
|
-
const reload = !!(change && change.propose);
|
|
89
|
-
return { origin, file, hunk, blockId, patchAdd, patchRevert, dep, reload };
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const makeDepItems = (origin, fileItems, hidden, summary) => {
|
|
93
|
-
const ordered = orderedChanges(summary.changes);
|
|
94
|
-
if (!ordered.length) {
|
|
95
|
-
const oldCount = summary.oldCount ?? 0;
|
|
96
|
-
const newCount = summary.newCount ?? 0;
|
|
97
|
-
if (oldCount === newCount) return [];
|
|
98
|
-
return [makeDepItem(origin, fileItems, hidden, null, summary, 0)];
|
|
99
|
-
}
|
|
100
|
-
const items = [];
|
|
101
|
-
let blockId = 0;
|
|
102
|
-
for (const change of ordered) {
|
|
103
|
-
const made = makeDepItem(
|
|
104
|
-
origin,
|
|
105
|
-
fileItems,
|
|
106
|
-
hidden,
|
|
107
|
-
change,
|
|
108
|
-
summary,
|
|
109
|
-
blockId,
|
|
110
|
-
);
|
|
111
|
-
items.push(made);
|
|
112
|
-
blockId += 1;
|
|
113
|
-
}
|
|
114
|
-
return items;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const stubFileItem = (rel, origin) => {
|
|
118
|
-
const file = {
|
|
119
|
-
oldPath: rel,
|
|
120
|
-
newPath: rel,
|
|
121
|
-
isNew: false,
|
|
122
|
-
isDeleted: false,
|
|
123
|
-
isBinary: false,
|
|
124
|
-
preamble: [],
|
|
125
|
-
hunks: [],
|
|
126
|
-
};
|
|
127
|
-
const hunk = null;
|
|
128
|
-
const blockId = 0;
|
|
129
|
-
const patchAdd = '';
|
|
130
|
-
const patchRevert = '';
|
|
131
|
-
return { origin, file, hunk, blockId, patchAdd, patchRevert };
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
module.exports = { makeDepItems, stubFileItem };
|
package/lib/deps/manifest.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const path = require('node:path');
|
|
4
|
-
|
|
5
|
-
const MANIFEST = 'package.json';
|
|
6
|
-
const LOCKFILE = 'package-lock.json';
|
|
7
|
-
const DEP_KIND = { [MANIFEST]: 'manifest', [LOCKFILE]: 'lockfile' };
|
|
8
|
-
const SECTION_KEYS = [
|
|
9
|
-
'dependencies',
|
|
10
|
-
'devDependencies',
|
|
11
|
-
'optionalDependencies',
|
|
12
|
-
'peerDependencies',
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
const posixRel = (rel) => {
|
|
16
|
-
const raw = `${rel ?? ''}`;
|
|
17
|
-
return raw.replaceAll('\\', '/');
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const depFileMeta = (rel) => {
|
|
21
|
-
const normalized = posixRel(rel);
|
|
22
|
-
if (!normalized) return null;
|
|
23
|
-
const base = path.posix.basename(normalized);
|
|
24
|
-
const kind = DEP_KIND[base];
|
|
25
|
-
if (!kind) return null;
|
|
26
|
-
const dir = path.posix.dirname(normalized);
|
|
27
|
-
return { kind, dir, base, rel: normalized };
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const relOf = (dir, name) => (dir === '.' ? name : `${dir}/${name}`);
|
|
31
|
-
|
|
32
|
-
const listFilePath = (rel) => {
|
|
33
|
-
const meta = depFileMeta(rel);
|
|
34
|
-
if (meta && meta.kind === 'lockfile') return relOf(meta.dir, MANIFEST);
|
|
35
|
-
return posixRel(rel);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const parseJson = (text) => {
|
|
39
|
-
if (!text || !`${text}`.trim()) return null;
|
|
40
|
-
try {
|
|
41
|
-
const data = JSON.parse(text);
|
|
42
|
-
if (!data || typeof data !== 'object' || Array.isArray(data)) return null;
|
|
43
|
-
return data;
|
|
44
|
-
} catch {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const emptySectionMaps = () => {
|
|
50
|
-
const maps = {};
|
|
51
|
-
for (const key of SECTION_KEYS) maps[key] = new Map();
|
|
52
|
-
return maps;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const readSectionMap = (pkg, key) => {
|
|
56
|
-
const map = new Map();
|
|
57
|
-
const raw = pkg ? pkg[key] : null;
|
|
58
|
-
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return map;
|
|
59
|
-
for (const name of Object.keys(raw)) {
|
|
60
|
-
const version = raw[name];
|
|
61
|
-
if (typeof version === 'string') map.set(name, version);
|
|
62
|
-
}
|
|
63
|
-
return map;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const readSections = (pkg) => {
|
|
67
|
-
const maps = emptySectionMaps();
|
|
68
|
-
if (!pkg) return maps;
|
|
69
|
-
for (const key of SECTION_KEYS) maps[key] = readSectionMap(pkg, key);
|
|
70
|
-
return maps;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const lockRootSections = (lock) => {
|
|
74
|
-
if (!lock) return emptySectionMaps();
|
|
75
|
-
const packages = lock.packages;
|
|
76
|
-
const root = packages && typeof packages === 'object' ? packages[''] : null;
|
|
77
|
-
const src = root && typeof root === 'object' ? root : lock;
|
|
78
|
-
return readSections(src);
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const lockEntries = (lock) => {
|
|
82
|
-
const versions = new Map();
|
|
83
|
-
if (!lock) return versions;
|
|
84
|
-
const packages = lock.packages;
|
|
85
|
-
if (packages && typeof packages === 'object') {
|
|
86
|
-
for (const key of Object.keys(packages)) {
|
|
87
|
-
const entry = packages[key];
|
|
88
|
-
if (!key.startsWith('node_modules/')) continue;
|
|
89
|
-
if (key.includes('/node_modules/')) continue;
|
|
90
|
-
if (!entry || typeof entry.version !== 'string') continue;
|
|
91
|
-
const name = key.slice('node_modules/'.length);
|
|
92
|
-
versions.set(name, entry.version);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const deps = lock.dependencies;
|
|
96
|
-
if (!deps || typeof deps !== 'object') return versions;
|
|
97
|
-
for (const name of Object.keys(deps)) {
|
|
98
|
-
const entry = deps[name];
|
|
99
|
-
if (versions.has(name)) continue;
|
|
100
|
-
if (!entry || typeof entry.version !== 'string') continue;
|
|
101
|
-
versions.set(name, entry.version);
|
|
102
|
-
}
|
|
103
|
-
return versions;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const lockPackageCount = (lock) => {
|
|
107
|
-
if (!lock) return 0;
|
|
108
|
-
const packages = lock.packages;
|
|
109
|
-
if (packages && typeof packages === 'object') {
|
|
110
|
-
let count = 0;
|
|
111
|
-
for (const key of Object.keys(packages)) {
|
|
112
|
-
if (key !== '') count += 1;
|
|
113
|
-
}
|
|
114
|
-
return count;
|
|
115
|
-
}
|
|
116
|
-
const deps = lock.dependencies;
|
|
117
|
-
if (!deps || typeof deps !== 'object') return 0;
|
|
118
|
-
return Object.keys(deps).length;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const cloneJson = (value) => JSON.parse(JSON.stringify(value ?? null));
|
|
122
|
-
|
|
123
|
-
const detectIndent = (text) => {
|
|
124
|
-
const match = /\n([ \t]+)"/.exec(text);
|
|
125
|
-
if (!match) return 2;
|
|
126
|
-
return match[1];
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const stringifyJson = (value, original) => {
|
|
130
|
-
const indent = detectIndent(original || '');
|
|
131
|
-
const body = JSON.stringify(value, null, indent);
|
|
132
|
-
return `${body}\n`;
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
module.exports = {
|
|
136
|
-
MANIFEST,
|
|
137
|
-
LOCKFILE,
|
|
138
|
-
DEP_KIND,
|
|
139
|
-
SECTION_KEYS,
|
|
140
|
-
posixRel,
|
|
141
|
-
depFileMeta,
|
|
142
|
-
relOf,
|
|
143
|
-
listFilePath,
|
|
144
|
-
parseJson,
|
|
145
|
-
emptySectionMaps,
|
|
146
|
-
readSections,
|
|
147
|
-
lockRootSections,
|
|
148
|
-
lockEntries,
|
|
149
|
-
lockPackageCount,
|
|
150
|
-
cloneJson,
|
|
151
|
-
stringifyJson,
|
|
152
|
-
};
|
package/lib/deps/merge.js
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const manifest = require('./manifest.js');
|
|
4
|
-
const { SECTION_KEYS, parseJson, cloneJson, stringifyJson } = manifest;
|
|
5
|
-
|
|
6
|
-
const parseFieldValue = (text) => {
|
|
7
|
-
try {
|
|
8
|
-
return JSON.parse(text);
|
|
9
|
-
} catch {
|
|
10
|
-
return text;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const setSectionEntry = (pkg, section, name, version) => {
|
|
15
|
-
if (!version) {
|
|
16
|
-
const map = pkg[section];
|
|
17
|
-
if (!map || typeof map !== 'object') return;
|
|
18
|
-
delete map[name];
|
|
19
|
-
if (!Object.keys(map).length) delete pkg[section];
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const map = pkg[section];
|
|
23
|
-
if (!map || typeof map !== 'object') pkg[section] = {};
|
|
24
|
-
pkg[section][name] = version;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const dropsEntry = (change, side) => {
|
|
28
|
-
if (side === 'new') return change.action === 'removed';
|
|
29
|
-
return change.action === 'added';
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const applyManifestChange = (pkg, change, side) => {
|
|
33
|
-
if (change.section === 'resolved') return pkg;
|
|
34
|
-
const value = side === 'new' ? change.to : change.from;
|
|
35
|
-
if (change.section === 'field') {
|
|
36
|
-
if (value === '') {
|
|
37
|
-
delete pkg[change.name];
|
|
38
|
-
return pkg;
|
|
39
|
-
}
|
|
40
|
-
pkg[change.name] = parseFieldValue(value);
|
|
41
|
-
return pkg;
|
|
42
|
-
}
|
|
43
|
-
const version = dropsEntry(change, side) ? '' : value;
|
|
44
|
-
setSectionEntry(pkg, change.section, change.name, version);
|
|
45
|
-
return pkg;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const ensureLockRoot = (lock) => {
|
|
49
|
-
if (!lock.packages || typeof lock.packages !== 'object') {
|
|
50
|
-
lock.packages = {};
|
|
51
|
-
}
|
|
52
|
-
const root = lock.packages[''];
|
|
53
|
-
if (!root || typeof root !== 'object') lock.packages[''] = {};
|
|
54
|
-
return lock.packages[''];
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const lockNodeKey = (name) => `node_modules/${name}`;
|
|
58
|
-
|
|
59
|
-
const applyLegacyLockDep = (lock, change, side, src) => {
|
|
60
|
-
const deps = lock.dependencies;
|
|
61
|
-
if (!deps || typeof deps !== 'object') return;
|
|
62
|
-
if (dropsEntry(change, side)) {
|
|
63
|
-
delete deps[change.name];
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const srcDeps = src && src.dependencies;
|
|
67
|
-
if (!srcDeps || typeof srcDeps !== 'object') return;
|
|
68
|
-
const entry = srcDeps[change.name];
|
|
69
|
-
if (entry) deps[change.name] = cloneJson(entry);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const applyLockChange = (lock, change, side, oldLock, newLock) => {
|
|
73
|
-
if (change.section === 'field') return lock;
|
|
74
|
-
const src = side === 'new' ? newLock : oldLock;
|
|
75
|
-
if (change.section !== 'resolved') {
|
|
76
|
-
const root = ensureLockRoot(lock);
|
|
77
|
-
applyManifestChange(root, change, side);
|
|
78
|
-
applyLegacyLockDep(lock, change, side, src);
|
|
79
|
-
}
|
|
80
|
-
const packages = lock.packages;
|
|
81
|
-
if (!packages || typeof packages !== 'object') return lock;
|
|
82
|
-
const key = lockNodeKey(change.name);
|
|
83
|
-
if (dropsEntry(change, side)) {
|
|
84
|
-
delete packages[key];
|
|
85
|
-
return lock;
|
|
86
|
-
}
|
|
87
|
-
const srcPkgs = src && src.packages;
|
|
88
|
-
if (!srcPkgs || typeof srcPkgs !== 'object') return lock;
|
|
89
|
-
const entry = srcPkgs[key];
|
|
90
|
-
if (entry) packages[key] = cloneJson(entry);
|
|
91
|
-
return lock;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const seedManifest = (oldObj, newObj) => {
|
|
95
|
-
const base = cloneJson(oldObj) || {};
|
|
96
|
-
if (!newObj) return base;
|
|
97
|
-
for (const key of Object.keys(newObj)) {
|
|
98
|
-
const value = newObj[key];
|
|
99
|
-
if (SECTION_KEYS.includes(key)) continue;
|
|
100
|
-
if (Object.hasOwn(base, key)) continue;
|
|
101
|
-
base[key] = cloneJson(value);
|
|
102
|
-
}
|
|
103
|
-
return base;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const mergeDepFile = (baseText, oldText, newText, change, side, kind) => {
|
|
107
|
-
const oldObj = parseJson(oldText);
|
|
108
|
-
const newObj = parseJson(newText);
|
|
109
|
-
const parsedBase = parseJson(baseText);
|
|
110
|
-
let base;
|
|
111
|
-
if (parsedBase) base = cloneJson(parsedBase);
|
|
112
|
-
else if (kind === 'manifest') base = seedManifest(oldObj, newObj);
|
|
113
|
-
else base = cloneJson(oldObj) || {};
|
|
114
|
-
if (kind === 'lockfile') applyLockChange(base, change, side, oldObj, newObj);
|
|
115
|
-
else applyManifestChange(base, change, side);
|
|
116
|
-
const original = baseText || newText || oldText || '';
|
|
117
|
-
return stringifyJson(base, original);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
module.exports = { mergeDepFile };
|