reslop 0.2.5 → 0.2.7
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 +22 -1
- package/LICENSE +1 -1
- package/README.md +11 -11
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +72 -19
- package/lib/api.js +1 -1
- package/lib/capabilities.js +8 -8
- package/lib/cli.js +61 -75
- package/lib/clipboard.js +39 -47
- package/lib/dashboard/git.js +128 -0
- package/lib/dashboard/model.js +357 -0
- package/lib/dashboard/npm.js +290 -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 +79 -91
- package/lib/find.js +61 -0
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +148 -272
- package/lib/git-reword-todo.js +5 -13
- package/lib/git-worktree.js +161 -214
- 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 +75 -83
- 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 +412 -347
- package/lib/render/commits.js +160 -361
- package/lib/render/dash-activity.js +212 -0
- package/lib/render/dash-blocks.js +496 -0
- package/lib/render/dash-table.js +295 -0
- package/lib/render/dashboard.js +62 -0
- package/lib/render/diff.js +123 -258
- package/lib/render/files.js +60 -86
- package/lib/render/frame.js +82 -117
- package/lib/render/notes.js +150 -210
- package/lib/render/npm.js +213 -177
- package/lib/render/packages.js +93 -0
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +77 -172
- package/lib/render/render.js +5 -14
- package/lib/render/report.js +43 -0
- package/lib/render/repos.js +226 -0
- package/lib/render/search.js +25 -0
- package/lib/render/tiles.js +355 -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 +69 -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 +189 -65
- package/lib/session/branches.js +164 -222
- package/lib/session/change-actions.js +49 -119
- package/lib/session/commit.js +298 -352
- package/lib/session/compose.js +572 -715
- package/lib/session/dashboard.js +530 -0
- package/lib/session/dispatch.js +197 -171
- package/lib/session/files-pane.js +92 -45
- package/lib/session/find.js +94 -0
- package/lib/session/items.js +6 -17
- package/lib/session/lifecycle.js +420 -466
- package/lib/session/load.js +1 -14
- package/lib/session/navigation.js +4 -2
- package/lib/session/npm.js +403 -420
- package/lib/session/ops.js +5 -13
- package/lib/session/packages.js +143 -0
- package/lib/session/pointer.js +30 -14
- package/lib/session/progress.js +39 -30
- package/lib/session/review.js +1 -3
- package/lib/session/tasks.js +277 -236
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -132
- package/lib/session/view.js +59 -80
- package/lib/session/watch.js +201 -212
- package/lib/session/workspace.js +455 -0
- package/lib/session.js +95 -161
- package/lib/update.js +44 -111
- package/lib/utilities.js +46 -88
- package/lib/workspace.js +166 -0
- package/lib/wrap.js +29 -55
- package/package.json +1 -1
package/lib/session.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const render = require('./render/render.js');
|
|
4
|
+
const { renderFrame } = render;
|
|
4
5
|
const keys = require('./keys.js');
|
|
6
|
+
const { decodeChunk } = keys;
|
|
5
7
|
const review = require('./review.js');
|
|
8
|
+
const { AUTOSAVE_MS, hasNotes } = review;
|
|
6
9
|
const files = require('./files.js');
|
|
7
10
|
const { makeTaskItem } = files;
|
|
8
|
-
const { renderFrame } = render;
|
|
9
|
-
const { decodeChunk } = keys;
|
|
10
|
-
const { AUTOSAVE_MS, hasNotes } = review;
|
|
11
11
|
const capabilities = require('./capabilities.js');
|
|
12
|
+
const { sessionCapabilities } = capabilities;
|
|
12
13
|
const actions = require('./session/actions.js');
|
|
13
14
|
const { LIST_PANES } = actions;
|
|
14
|
-
const { sessionCapabilities } = capabilities;
|
|
15
15
|
const terminal = require('./session/terminal.js');
|
|
16
|
-
const {
|
|
16
|
+
const { Terminal, LEAVE_TERM } = terminal;
|
|
17
17
|
const load = require('./session/load.js');
|
|
18
18
|
const { LoadCoordinator } = load;
|
|
19
19
|
const items = require('./session/items.js');
|
|
@@ -25,31 +25,31 @@ const { ReviewController } = sessionReview;
|
|
|
25
25
|
const update = require('./session/update.js');
|
|
26
26
|
const { UpdateCoordinator } = update;
|
|
27
27
|
const progress = require('./session/progress.js');
|
|
28
|
-
const {
|
|
28
|
+
const { Progress } = progress;
|
|
29
29
|
const compose = require('./session/compose.js');
|
|
30
|
-
const {
|
|
30
|
+
const { Composer } = compose;
|
|
31
31
|
const ops = require('./session/ops.js');
|
|
32
32
|
const { OpsRunner } = ops;
|
|
33
|
-
const changeActions = require('./session/change-actions.js');
|
|
34
|
-
const { createChangeActions } = changeActions;
|
|
35
33
|
const commit = require('./session/commit.js');
|
|
36
|
-
const {
|
|
34
|
+
const { CommitController } = commit;
|
|
37
35
|
const branches = require('./session/branches.js');
|
|
38
|
-
const {
|
|
36
|
+
const { BranchController } = branches;
|
|
39
37
|
const npm = require('./session/npm.js');
|
|
40
|
-
const {
|
|
38
|
+
const { NpmController } = npm;
|
|
39
|
+
const packages = require('./session/packages.js');
|
|
40
|
+
const { PackageController } = packages;
|
|
41
41
|
const accessors = require('./session/accessors.js');
|
|
42
|
-
const { bindAccessors, bindGetters
|
|
42
|
+
const { bindAccessors, bindGetters } = accessors;
|
|
43
43
|
const view = require('./session/view.js');
|
|
44
|
-
const { createView } = view;
|
|
45
44
|
const filesPane = require('./session/files-pane.js');
|
|
46
|
-
const { createFilesPane } = filesPane;
|
|
47
45
|
const lifecycle = require('./session/lifecycle.js');
|
|
48
|
-
const {
|
|
49
|
-
const pointer = require('./session/pointer.js');
|
|
50
|
-
const { createPointer } = pointer;
|
|
46
|
+
const { Lifecycle } = lifecycle;
|
|
51
47
|
const dispatch = require('./session/dispatch.js');
|
|
52
|
-
const {
|
|
48
|
+
const { dispatchAction, confirmChoice, handleEvent } = dispatch;
|
|
49
|
+
const dashboard = require('./session/dashboard.js');
|
|
50
|
+
const { Dashboard } = dashboard;
|
|
51
|
+
const workspace = require('./session/workspace.js');
|
|
52
|
+
const { Workspace } = workspace;
|
|
53
53
|
|
|
54
54
|
const PROGRESS_MS = 160;
|
|
55
55
|
|
|
@@ -77,7 +77,6 @@ const COMPOSER_FIELDS = [
|
|
|
77
77
|
'composeKind',
|
|
78
78
|
'commitKind',
|
|
79
79
|
'composeTaskId',
|
|
80
|
-
'composeBaseline',
|
|
81
80
|
'templateIndex',
|
|
82
81
|
'templateFocus',
|
|
83
82
|
];
|
|
@@ -90,11 +89,6 @@ const assignOptions = (session, options) => {
|
|
|
90
89
|
session.stdout = options.stdout;
|
|
91
90
|
session.proc = options.proc ?? process;
|
|
92
91
|
session.color = options.color ?? true;
|
|
93
|
-
session.getSize = () => {
|
|
94
|
-
const width = session.stdout.columns ?? 80;
|
|
95
|
-
const height = session.stdout.rows ?? 24;
|
|
96
|
-
return { width, height };
|
|
97
|
-
};
|
|
98
92
|
session.rev = options.rev ?? null;
|
|
99
93
|
session.revShort = '';
|
|
100
94
|
session.sourceLabel = options.sourceLabel ?? '';
|
|
@@ -107,41 +101,35 @@ const assignOptions = (session, options) => {
|
|
|
107
101
|
session.outdatedMap = options.outdatedMap;
|
|
108
102
|
session.auditMap = options.auditMap;
|
|
109
103
|
session.updateOpts = options.update;
|
|
110
|
-
session.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
104
|
+
session.dashboardHome = options.startPane === 'dashboard';
|
|
105
|
+
session.workspaceRoot = options.workspace ? options.workspace.root : '';
|
|
106
|
+
session.workspaceInfo = options.workspace ?? null;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const assignParts = (session, options) => {
|
|
110
|
+
const { stdin, stdout, proc } = session;
|
|
111
|
+
session.term = new Terminal({ stdin, stdout, proc });
|
|
115
112
|
session.loader = new LoadCoordinator();
|
|
116
113
|
session.collection = new ItemCollection();
|
|
117
114
|
session.nav = new Navigation({ startPane: options.startPane ?? 'files' });
|
|
118
115
|
session.review = new ReviewController();
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
);
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const assignComposer = (session) => {
|
|
127
|
-
session.composer = createComposer({
|
|
128
|
-
nav: session.nav,
|
|
129
|
-
review: session.review,
|
|
130
|
-
ui: session,
|
|
131
|
-
});
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const assignControllers = (session) => {
|
|
116
|
+
const tick = () => session.tickProgress();
|
|
117
|
+
session.progress = new Progress(session.term, tick, PROGRESS_MS);
|
|
118
|
+
session.updater = new UpdateCoordinator(session);
|
|
119
|
+
session.composer = new Composer(session);
|
|
135
120
|
session.ops = new OpsRunner(session);
|
|
136
|
-
session.
|
|
137
|
-
session.
|
|
138
|
-
session.
|
|
139
|
-
session.
|
|
121
|
+
session.commits = new CommitController(session);
|
|
122
|
+
session.gitBranches = new BranchController(session);
|
|
123
|
+
session.npm = new NpmController(session);
|
|
124
|
+
session.packages = new PackageController(session);
|
|
125
|
+
session.dashboard = new Dashboard(session);
|
|
126
|
+
session.workspace = new Workspace(session);
|
|
127
|
+
session.lifecycle = new Lifecycle(session);
|
|
140
128
|
};
|
|
141
129
|
|
|
142
|
-
const
|
|
130
|
+
const bindFields = (session) => {
|
|
143
131
|
bindAccessors(session, session.nav, NAV_FIELDS);
|
|
144
|
-
bindAccessors(session, session.composer
|
|
132
|
+
bindAccessors(session, session.composer, COMPOSER_FIELDS);
|
|
145
133
|
bindAccessors(session, session.loader, ['pendingExtras']);
|
|
146
134
|
bindGetters(session, session.loader, ['didLoad']);
|
|
147
135
|
bindAccessors(session, session.collection, ['items']);
|
|
@@ -150,76 +138,37 @@ const bindSessionAccessors = (session) => {
|
|
|
150
138
|
bindAccessors(session, session.ops, ['gitBusy', 'busy']);
|
|
151
139
|
bindAccessors(session, session.gitBranches, ['branches', 'dropName']);
|
|
152
140
|
bindGetters(session, session.term, ['lastFrame', 'lastSize']);
|
|
153
|
-
bindAlias(session, 'notes', () => session.review.store);
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const bindViewer = (session) => {
|
|
157
|
-
session.viewer = createView({
|
|
158
|
-
nav: session.nav,
|
|
159
|
-
composer: session.composer,
|
|
160
|
-
collection: session.collection,
|
|
161
|
-
review: session.review,
|
|
162
|
-
gitBranches: session.gitBranches,
|
|
163
|
-
commits: session.commits,
|
|
164
|
-
npm: session.npm,
|
|
165
|
-
updater: session.updater,
|
|
166
|
-
ui: session,
|
|
167
|
-
});
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const bindLifecycle = (session) => {
|
|
171
|
-
session.lifecycle = createLifecycle({
|
|
172
|
-
loader: session.loader,
|
|
173
|
-
collection: session.collection,
|
|
174
|
-
review: session.review,
|
|
175
|
-
nav: session.nav,
|
|
176
|
-
ops: session.ops,
|
|
177
|
-
updater: session.updater,
|
|
178
|
-
loadConfig: {
|
|
179
|
-
repo: session.repo,
|
|
180
|
-
cwd: session.cwd,
|
|
181
|
-
paths: session.paths,
|
|
182
|
-
audit: session.audit,
|
|
183
|
-
outdatedMap: session.outdatedMap,
|
|
184
|
-
auditMap: session.auditMap,
|
|
185
|
-
},
|
|
186
|
-
ui: session,
|
|
187
|
-
});
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const bindDispatch = (session) => {
|
|
191
|
-
session.dispatcher = createDispatcher(session);
|
|
192
|
-
session.pointer = createPointer(session);
|
|
193
|
-
session.input = createInput(session);
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
const composeSession = (session, options) => {
|
|
197
|
-
assignOptions(session, options);
|
|
198
|
-
session.updater = new UpdateCoordinator(session);
|
|
199
|
-
assignComposer(session);
|
|
200
|
-
assignControllers(session);
|
|
201
|
-
bindSessionAccessors(session);
|
|
202
|
-
bindViewer(session);
|
|
203
|
-
session.filesPane = createFilesPane(session);
|
|
204
|
-
bindLifecycle(session);
|
|
205
|
-
bindDispatch(session);
|
|
206
141
|
};
|
|
207
142
|
|
|
208
143
|
class Session {
|
|
209
144
|
constructor(options) {
|
|
210
|
-
|
|
145
|
+
assignOptions(this, options);
|
|
146
|
+
assignParts(this, options);
|
|
147
|
+
bindFields(this);
|
|
211
148
|
this.resetState();
|
|
212
149
|
}
|
|
213
150
|
|
|
151
|
+
get notes() {
|
|
152
|
+
return this.review.store;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
getSize() {
|
|
156
|
+
const width = this.stdout.columns ?? 80;
|
|
157
|
+
const height = this.stdout.rows ?? 24;
|
|
158
|
+
return { width, height };
|
|
159
|
+
}
|
|
160
|
+
|
|
214
161
|
resetState() {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
162
|
+
this.collection.reset();
|
|
163
|
+
this.nav.reset();
|
|
164
|
+
this.review.reset();
|
|
165
|
+
this.composer.reset();
|
|
166
|
+
this.ops.reset();
|
|
167
|
+
this.gitBranches.reset();
|
|
168
|
+
this.commits.reset();
|
|
169
|
+
this.npm.reset();
|
|
170
|
+
this.dashboard.reset();
|
|
171
|
+
this.workspace.reset();
|
|
223
172
|
this.top = this.cwd;
|
|
224
173
|
this.branch = '';
|
|
225
174
|
this.status = '';
|
|
@@ -233,12 +182,12 @@ class Session {
|
|
|
233
182
|
this.loadError = null;
|
|
234
183
|
this.uiOpen = false;
|
|
235
184
|
this.finishReadLoop = null;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
185
|
+
this.lifecycle.stopWatch();
|
|
186
|
+
this.lifecycle.clearNpmExtras();
|
|
187
|
+
this.term.resetCache();
|
|
188
|
+
this.loader.reset();
|
|
189
|
+
this.updater.reset();
|
|
190
|
+
this.progress.clear();
|
|
242
191
|
}
|
|
243
192
|
|
|
244
193
|
ensureRepo() {
|
|
@@ -271,8 +220,7 @@ class Session {
|
|
|
271
220
|
}
|
|
272
221
|
|
|
273
222
|
paint() {
|
|
274
|
-
if (
|
|
275
|
-
this.draw();
|
|
223
|
+
if (this.uiOpen) this.draw();
|
|
276
224
|
}
|
|
277
225
|
|
|
278
226
|
draw() {
|
|
@@ -294,6 +242,8 @@ class Session {
|
|
|
294
242
|
const composing = this.mode === 'compose';
|
|
295
243
|
this.term.paint(frame, size, composing ? frame.cursor : null);
|
|
296
244
|
this.scheduleAutosave();
|
|
245
|
+
this.dashboard.afterDraw();
|
|
246
|
+
this.workspace.afterDraw();
|
|
297
247
|
}
|
|
298
248
|
|
|
299
249
|
scheduleAutosave() {
|
|
@@ -304,19 +254,11 @@ class Session {
|
|
|
304
254
|
}
|
|
305
255
|
|
|
306
256
|
view() {
|
|
307
|
-
return
|
|
257
|
+
return view.view(this);
|
|
308
258
|
}
|
|
309
259
|
|
|
310
260
|
fileList() {
|
|
311
|
-
return
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
counts() {
|
|
315
|
-
return this.viewer.counts();
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
viewStatus() {
|
|
319
|
-
return this.viewer.viewStatus();
|
|
261
|
+
return view.fileList(this);
|
|
320
262
|
}
|
|
321
263
|
|
|
322
264
|
current() {
|
|
@@ -324,31 +266,35 @@ class Session {
|
|
|
324
266
|
}
|
|
325
267
|
|
|
326
268
|
fileCursorEntry() {
|
|
327
|
-
return
|
|
269
|
+
return filesPane.fileCursorEntry(this);
|
|
328
270
|
}
|
|
329
271
|
|
|
330
272
|
clampIndex() {
|
|
331
|
-
|
|
273
|
+
filesPane.clampIndex(this);
|
|
332
274
|
}
|
|
333
275
|
|
|
334
276
|
syncReviewPath() {
|
|
335
|
-
|
|
277
|
+
filesPane.syncReviewPath(this);
|
|
336
278
|
}
|
|
337
279
|
|
|
338
280
|
syncFileCursor() {
|
|
339
|
-
|
|
281
|
+
filesPane.syncFileCursor(this);
|
|
340
282
|
}
|
|
341
283
|
|
|
342
284
|
showFiles() {
|
|
343
|
-
|
|
285
|
+
filesPane.showFiles(this);
|
|
344
286
|
}
|
|
345
287
|
|
|
346
288
|
dispatch(action) {
|
|
347
|
-
this
|
|
289
|
+
dispatchAction(this, action);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
confirmChoice(key) {
|
|
293
|
+
confirmChoice(this, key);
|
|
348
294
|
}
|
|
349
295
|
|
|
350
296
|
handleEvent(event) {
|
|
351
|
-
|
|
297
|
+
handleEvent(this, event);
|
|
352
298
|
}
|
|
353
299
|
|
|
354
300
|
pushInput(text) {
|
|
@@ -376,7 +322,7 @@ class Session {
|
|
|
376
322
|
this.status = result.error.message;
|
|
377
323
|
return false;
|
|
378
324
|
}
|
|
379
|
-
|
|
325
|
+
this.lifecycle.noteReviewStamp();
|
|
380
326
|
return result.wrote;
|
|
381
327
|
}
|
|
382
328
|
|
|
@@ -385,22 +331,11 @@ class Session {
|
|
|
385
331
|
if (result.kind === 'commit') this.commits.finishGitCommit();
|
|
386
332
|
if (result.kind === 'branch') this.gitBranches.finishCreateBranch();
|
|
387
333
|
if (result.kind === 'npm') this.npm.finishEdit();
|
|
334
|
+
if (result.kind === 'package') this.packages.finishAdd();
|
|
388
335
|
}
|
|
389
336
|
|
|
390
337
|
selectTemplate(index) {
|
|
391
|
-
this.runComposeCommand(this.composer.selectTemplate(index));
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
idleNoteText() {
|
|
395
|
-
return this.composer.idleNoteText();
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
shownTemplates() {
|
|
399
|
-
return this.composer.shownTemplates();
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
startDraftCompose() {
|
|
403
|
-
this.composer.startDraftCompose();
|
|
338
|
+
this.runComposeCommand(this.composer.templates.selectTemplate(index));
|
|
404
339
|
}
|
|
405
340
|
|
|
406
341
|
autosave() {
|
|
@@ -461,6 +396,7 @@ class Session {
|
|
|
461
396
|
this.uiOpen = true;
|
|
462
397
|
this.term.enter();
|
|
463
398
|
try {
|
|
399
|
+
if (this.nav.pane === 'repos') this.workspace.start();
|
|
464
400
|
this.openLoad();
|
|
465
401
|
this.openUpdate();
|
|
466
402
|
this.draw();
|
|
@@ -487,6 +423,8 @@ class Session {
|
|
|
487
423
|
if (settled) return;
|
|
488
424
|
settled = true;
|
|
489
425
|
this.lifecycle.stopWatch();
|
|
426
|
+
this.dashboard.stop();
|
|
427
|
+
this.workspace.stop();
|
|
490
428
|
this.term.stopListening();
|
|
491
429
|
this.progress.clear();
|
|
492
430
|
this.term.clearTimers();
|
|
@@ -503,16 +441,12 @@ class Session {
|
|
|
503
441
|
if (this.done) return void finish();
|
|
504
442
|
this.draw();
|
|
505
443
|
};
|
|
506
|
-
this.term.startListening({
|
|
507
|
-
onData,
|
|
508
|
-
onResize: () => this.draw(),
|
|
509
|
-
});
|
|
444
|
+
this.term.startListening({ onData, onResize: () => this.draw() });
|
|
510
445
|
this.lifecycle.startWatch();
|
|
446
|
+
if (this.dashboardHome) this.dashboard.start();
|
|
447
|
+
if (this.nav.pane === 'repos') this.workspace.start();
|
|
511
448
|
});
|
|
512
449
|
}
|
|
513
450
|
}
|
|
514
451
|
|
|
515
|
-
module.exports = {
|
|
516
|
-
LEAVE_TERM,
|
|
517
|
-
Session,
|
|
518
|
-
};
|
|
452
|
+
module.exports = { LEAVE_TERM, Session };
|
package/lib/update.js
CHANGED
|
@@ -21,19 +21,10 @@ const INSTALL_MS = 120000;
|
|
|
21
21
|
const REGISTRY = 'https://registry.npmjs.org';
|
|
22
22
|
|
|
23
23
|
const RELEASE = /^\d+\.\d+\.\d+$/;
|
|
24
|
-
const
|
|
25
|
-
checkedAt: 0,
|
|
26
|
-
compatible: '',
|
|
27
|
-
major: '',
|
|
28
|
-
skipped: '',
|
|
29
|
-
});
|
|
24
|
+
const NO_TARGETS = { compatible: '', major: '' };
|
|
30
25
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const isNpmInstall = (pkgDir) => {
|
|
34
|
-
const parent = path.basename(path.dirname(pkgDir));
|
|
35
|
-
return parent === 'node_modules';
|
|
36
|
-
};
|
|
26
|
+
const isNpmInstall = (pkgDir) =>
|
|
27
|
+
path.basename(path.dirname(pkgDir)) === 'node_modules';
|
|
37
28
|
|
|
38
29
|
const cacheFile = (env = process.env) => {
|
|
39
30
|
if (env.XDG_CACHE_HOME) {
|
|
@@ -49,29 +40,26 @@ const cacheFile = (env = process.env) => {
|
|
|
49
40
|
|
|
50
41
|
const readCache = (file) => {
|
|
51
42
|
try {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
const data = jsonParse(fs.readFileSync(file, 'utf8'));
|
|
44
|
+
if (isHashObject(data)) {
|
|
45
|
+
return {
|
|
46
|
+
checkedAt: parseInt(data.checkedAt, 10) || 0,
|
|
47
|
+
compatible: asText(data.compatible),
|
|
48
|
+
major: asText(data.major) || asText(data.latest),
|
|
49
|
+
skipped: asText(data.skipped) || asText(data.handled),
|
|
50
|
+
};
|
|
56
51
|
}
|
|
57
|
-
const checkedAt = toInt(data.checkedAt) || 0;
|
|
58
|
-
const compatible = asText(data.compatible);
|
|
59
|
-
const major = asText(data.major) || asText(data.latest);
|
|
60
|
-
const skipped = asText(data.skipped) || asText(data.handled);
|
|
61
|
-
return { checkedAt, compatible, major, skipped };
|
|
62
52
|
} catch {
|
|
63
|
-
|
|
53
|
+
// missing or unreadable cache
|
|
64
54
|
}
|
|
55
|
+
return { checkedAt: 0, compatible: '', major: '', skipped: '' };
|
|
65
56
|
};
|
|
66
57
|
|
|
67
58
|
const writeCache = (file, data) => {
|
|
59
|
+
const { checkedAt, compatible, major, skipped } = data;
|
|
60
|
+
const body = JSON.stringify({ checkedAt, compatible, major, skipped });
|
|
68
61
|
try {
|
|
69
62
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
70
|
-
const checkedAt = data.checkedAt ?? 0;
|
|
71
|
-
const compatible = data.compatible ?? '';
|
|
72
|
-
const major = data.major ?? '';
|
|
73
|
-
const skipped = data.skipped ?? '';
|
|
74
|
-
const body = JSON.stringify({ checkedAt, compatible, major, skipped });
|
|
75
63
|
fs.writeFileSync(file, `${body}\n`);
|
|
76
64
|
} catch {
|
|
77
65
|
// ignore cache write errors
|
|
@@ -79,76 +67,43 @@ const writeCache = (file, data) => {
|
|
|
79
67
|
};
|
|
80
68
|
|
|
81
69
|
const isFresh = (cache, now, interval = CHECK_INTERVAL_MS) => {
|
|
82
|
-
if (!cache ||
|
|
83
|
-
if (now < cache.checkedAt) return false;
|
|
70
|
+
if (!cache.checkedAt || now < cache.checkedAt) return false;
|
|
84
71
|
return now - cache.checkedAt < interval;
|
|
85
72
|
};
|
|
86
73
|
|
|
87
74
|
const listVersions = (data) => {
|
|
88
75
|
if (!data || typeof data !== 'object') return [];
|
|
89
76
|
const names = [];
|
|
90
|
-
|
|
91
|
-
if (isHashObject(map)) {
|
|
92
|
-
for (const name of Object.keys(map)) names.push(name);
|
|
93
|
-
}
|
|
77
|
+
if (isHashObject(data.versions)) names.push(...Object.keys(data.versions));
|
|
94
78
|
const tags = data['dist-tags'];
|
|
95
79
|
if (tags && typeof tags.latest === 'string') names.push(tags.latest);
|
|
96
80
|
if (typeof data.version === 'string') names.push(data.version);
|
|
97
|
-
|
|
98
|
-
for (const name of names) {
|
|
99
|
-
if (!RELEASE.test(name)) continue;
|
|
100
|
-
if (listed.includes(name)) continue;
|
|
101
|
-
listed.push(name);
|
|
102
|
-
}
|
|
103
|
-
return listed;
|
|
81
|
+
return [...new Set(names)].filter((name) => RELEASE.test(name));
|
|
104
82
|
};
|
|
105
83
|
|
|
106
|
-
const
|
|
84
|
+
const newer = (best, name) => {
|
|
107
85
|
if (!best) return name;
|
|
108
|
-
|
|
109
|
-
if (!prev || cmpVersion(ver, prev) > 0) return name;
|
|
110
|
-
return best;
|
|
86
|
+
return cmpVersion(parseVersion(name), parseVersion(best)) > 0 ? name : best;
|
|
111
87
|
};
|
|
112
88
|
|
|
113
89
|
const pickTargets = (current, names) => {
|
|
114
90
|
const from = parseVersion(current);
|
|
115
|
-
if (!from) return
|
|
91
|
+
if (!from) return NO_TARGETS;
|
|
116
92
|
let compatible = '';
|
|
117
93
|
let major = '';
|
|
118
94
|
for (const name of names) {
|
|
119
95
|
const ver = parseVersion(name);
|
|
120
|
-
if (!ver) continue;
|
|
121
96
|
if (cmpVersion(ver, from) <= 0) continue;
|
|
122
|
-
if (ver.major === from.major)
|
|
123
|
-
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if (ver.major > from.major) major = pickNewerName(major, name, ver);
|
|
97
|
+
if (ver.major === from.major) compatible = newer(compatible, name);
|
|
98
|
+
else if (ver.major > from.major) major = newer(major, name);
|
|
127
99
|
}
|
|
128
100
|
return { compatible, major };
|
|
129
101
|
};
|
|
130
102
|
|
|
131
|
-
const
|
|
132
|
-
const from = parseVersion(current);
|
|
133
|
-
const to = parseVersion(latest);
|
|
134
|
-
if (!from || !to || cmpVersion(to, from) <= 0) {
|
|
135
|
-
return { compatible: '', major: '' };
|
|
136
|
-
}
|
|
137
|
-
if (to.major > from.major) return { compatible: '', major: latest };
|
|
138
|
-
return { compatible: latest, major: '' };
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const planUpdate = (current, extra = {}) => {
|
|
103
|
+
const planUpdate = (current, targets) => {
|
|
142
104
|
const from = parseVersion(current);
|
|
143
105
|
if (!from) return { action: 'none' };
|
|
144
|
-
|
|
145
|
-
let major = extra.major ?? '';
|
|
146
|
-
const skipped = extra.skipped ?? extra.handled ?? '';
|
|
147
|
-
if (!compatible && !major && extra.latest) {
|
|
148
|
-
const classified = classifyLatest(current, extra.latest);
|
|
149
|
-
compatible = classified.compatible;
|
|
150
|
-
major = classified.major;
|
|
151
|
-
}
|
|
106
|
+
const { compatible, major, skipped } = targets;
|
|
152
107
|
const compatVer = parseVersion(compatible);
|
|
153
108
|
if (compatVer && compatVer.major === from.major) {
|
|
154
109
|
if (cmpVersion(compatVer, from) > 0) {
|
|
@@ -162,53 +117,40 @@ const planUpdate = (current, extra = {}) => {
|
|
|
162
117
|
return { action: 'confirm', current, latest: major };
|
|
163
118
|
};
|
|
164
119
|
|
|
165
|
-
const isEnabled = (options
|
|
166
|
-
if (options.enabled ===
|
|
167
|
-
|
|
168
|
-
const pkgDir = options.pkgDir ?? PKG_DIR;
|
|
169
|
-
return isNpmInstall(pkgDir);
|
|
120
|
+
const isEnabled = (options) => {
|
|
121
|
+
if (typeof options.enabled === 'boolean') return options.enabled;
|
|
122
|
+
return isNpmInstall(options.pkgDir ?? PKG_DIR);
|
|
170
123
|
};
|
|
171
124
|
|
|
172
|
-
const fetchTargets = async (current, options
|
|
173
|
-
const empty = { compatible: '', major: '' };
|
|
125
|
+
const fetchTargets = async (current, options) => {
|
|
174
126
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
175
|
-
if (typeof fetchImpl !== 'function') return
|
|
176
|
-
const
|
|
177
|
-
const url = `${REGISTRY}/${encoded}`;
|
|
127
|
+
if (typeof fetchImpl !== 'function') return NO_TARGETS;
|
|
128
|
+
const url = `${REGISTRY}/${encodeURIComponent(PKG_NAME)}`;
|
|
178
129
|
const headers = { accept: 'application/json' };
|
|
179
130
|
const signal = options.signal ?? AbortSignal.timeout(FETCH_MS);
|
|
180
131
|
const response = await fetchImpl(url, { headers, signal });
|
|
181
|
-
if (!response || !response.ok) return
|
|
132
|
+
if (!response || !response.ok) return NO_TARGETS;
|
|
182
133
|
const data = await response.json();
|
|
183
134
|
return pickTargets(current, listVersions(data));
|
|
184
135
|
};
|
|
185
136
|
|
|
186
|
-
const npmInstall = async (spec, extra = {}) => {
|
|
187
|
-
const timeout = extra.timeout ?? INSTALL_MS;
|
|
188
|
-
const result = await runProc(
|
|
189
|
-
npmBin(),
|
|
190
|
-
['install', '-g', spec],
|
|
191
|
-
npmOpts({ timeout }),
|
|
192
|
-
);
|
|
193
|
-
if (result.error) throw result.error;
|
|
194
|
-
if (result.status !== 0) {
|
|
195
|
-
throw new Error(oneLine(result.stderr, 'npm install failed'));
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
|
|
199
137
|
const installUpdate = async (version, options = {}) => {
|
|
200
138
|
if (typeof options.install === 'function') {
|
|
201
139
|
await options.install(version);
|
|
202
140
|
return;
|
|
203
141
|
}
|
|
204
|
-
const
|
|
205
|
-
|
|
142
|
+
const timeout = options.timeout ?? INSTALL_MS;
|
|
143
|
+
const args = ['install', '-g', `${PKG_NAME}@${version}`];
|
|
144
|
+
const result = await runProc(npmBin(), args, npmOpts({ timeout }));
|
|
145
|
+
if (result.error) throw result.error;
|
|
146
|
+
if (result.status !== 0) {
|
|
147
|
+
throw new Error(oneLine(result.stderr, 'npm install failed'));
|
|
148
|
+
}
|
|
206
149
|
};
|
|
207
150
|
|
|
208
151
|
const markSkipped = (version, options = {}) => {
|
|
209
152
|
const file = options.cacheFile ?? cacheFile(options.env);
|
|
210
|
-
|
|
211
|
-
writeCache(file, { ...cache, skipped: version });
|
|
153
|
+
writeCache(file, { ...readCache(file), skipped: version });
|
|
212
154
|
};
|
|
213
155
|
|
|
214
156
|
const checkUpdate = async (options = {}) => {
|
|
@@ -216,37 +158,28 @@ const checkUpdate = async (options = {}) => {
|
|
|
216
158
|
const now = Date.now();
|
|
217
159
|
const current = options.current ?? PKG_VERSION;
|
|
218
160
|
const file = options.cacheFile ?? cacheFile(options.env);
|
|
219
|
-
const interval = options.interval ?? CHECK_INTERVAL_MS;
|
|
220
161
|
const cache = readCache(file);
|
|
221
|
-
if (isFresh(cache, now, interval)) {
|
|
162
|
+
if (isFresh(cache, now, options.interval)) {
|
|
222
163
|
const plan = planUpdate(current, cache);
|
|
223
|
-
|
|
224
|
-
return plan;
|
|
164
|
+
return plan.action === 'install' ? { action: 'none' } : plan;
|
|
225
165
|
}
|
|
226
|
-
let targets =
|
|
166
|
+
let targets = NO_TARGETS;
|
|
227
167
|
try {
|
|
228
168
|
targets = await fetchTargets(current, options);
|
|
229
169
|
} catch {
|
|
230
170
|
// ignore registry errors
|
|
231
171
|
}
|
|
232
|
-
const next = {
|
|
233
|
-
...cache,
|
|
234
|
-
checkedAt: now,
|
|
235
|
-
compatible: targets.compatible,
|
|
236
|
-
major: targets.major,
|
|
237
|
-
};
|
|
238
172
|
if (!targets.compatible && !targets.major) {
|
|
239
173
|
writeCache(file, { ...cache, checkedAt: now });
|
|
240
174
|
return { action: 'none' };
|
|
241
175
|
}
|
|
176
|
+
const next = { ...cache, checkedAt: now, ...targets };
|
|
242
177
|
writeCache(file, next);
|
|
243
178
|
return planUpdate(current, next);
|
|
244
179
|
};
|
|
245
180
|
|
|
246
181
|
module.exports = {
|
|
247
182
|
CHECK_INTERVAL_MS,
|
|
248
|
-
parseVersion,
|
|
249
|
-
cmpVersion,
|
|
250
183
|
isNpmInstall,
|
|
251
184
|
cacheFile,
|
|
252
185
|
readCache,
|