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/session/watch.js
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
|
|
6
|
+
const runs = require('../runs.js');
|
|
7
|
+
const { isRunsRel } = runs;
|
|
8
|
+
|
|
6
9
|
const DEBOUNCE_MS = 200;
|
|
10
|
+
const UNKNOWN_PATH = '.';
|
|
11
|
+
const MODULES_STAMP = 'node_modules/.package-lock.json';
|
|
7
12
|
|
|
8
13
|
const SKIP_DIRS = ['node_modules', '.review', 'coverage', 'dist', '.cache'];
|
|
9
14
|
|
|
@@ -14,41 +19,30 @@ const GIT_WATCH_NAMES = [
|
|
|
14
19
|
'FETCH_HEAD',
|
|
15
20
|
'ORIG_HEAD',
|
|
16
21
|
'refs',
|
|
22
|
+
'rebase-merge',
|
|
23
|
+
'rebase-apply',
|
|
17
24
|
];
|
|
18
25
|
|
|
19
|
-
const linuxRecursiveNode = (version) => {
|
|
20
|
-
const parts = `${version}`.split('.');
|
|
21
|
-
const major = Number(parts[0]);
|
|
22
|
-
const minor = Number(parts[1]);
|
|
23
|
-
if (major > 19) return true;
|
|
24
|
-
return major === 19 && minor >= 1;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
26
|
const canWatchRecursive = (
|
|
28
27
|
platform = process.platform,
|
|
29
28
|
version = process.versions.node,
|
|
30
29
|
) => {
|
|
31
30
|
if (platform === 'win32' || platform === 'darwin') return true;
|
|
32
|
-
if (platform
|
|
33
|
-
|
|
31
|
+
if (platform !== 'linux') return false;
|
|
32
|
+
const [major, minor] = `${version}`.split('.').map(Number);
|
|
33
|
+
return major > 19 || (major === 19 && minor >= 1);
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
const
|
|
37
|
-
if (!name) return false;
|
|
38
|
-
if (name.endsWith('.lock')) return true;
|
|
39
|
-
if (name.endsWith('~')) return true;
|
|
40
|
-
if (name.endsWith('.swp') || name.endsWith('.swo')) return true;
|
|
41
|
-
if (name.startsWith('.#')) return true;
|
|
42
|
-
if (name === '.DS_Store') return true;
|
|
43
|
-
return false;
|
|
44
|
-
};
|
|
36
|
+
const IGNORED_SUFFIXES = ['.lock', '~', '.swp', '.swo'];
|
|
45
37
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
const ignoredName = (name) =>
|
|
39
|
+
IGNORED_SUFFIXES.some((suffix) => name.endsWith(suffix)) ||
|
|
40
|
+
name.startsWith('.#') ||
|
|
41
|
+
name === '.DS_Store';
|
|
42
|
+
|
|
43
|
+
const ignoredGitRel = ([, name = '', sub]) => {
|
|
44
|
+
if (name === 'logs' && sub === 'HEAD') return false;
|
|
45
|
+
return name !== '' && !GIT_WATCH_NAMES.includes(name);
|
|
52
46
|
};
|
|
53
47
|
|
|
54
48
|
const slashRel = (rel) => `${rel}`.replaceAll('\\', '/');
|
|
@@ -56,34 +50,24 @@ const slashRel = (rel) => `${rel}`.replaceAll('\\', '/');
|
|
|
56
50
|
const ignoredRel = (rel) => {
|
|
57
51
|
const norm = slashRel(rel);
|
|
58
52
|
if (!norm || norm === '.') return false;
|
|
53
|
+
if (norm === MODULES_STAMP) return false;
|
|
59
54
|
const parts = norm.split('/');
|
|
60
|
-
|
|
61
|
-
if (SKIP_DIRS.includes(part)) return true;
|
|
62
|
-
}
|
|
55
|
+
if (parts.some((part) => SKIP_DIRS.includes(part))) return true;
|
|
63
56
|
if (parts[0] === '.git') return ignoredGitRel(parts);
|
|
64
57
|
return ignoredName(parts[parts.length - 1]);
|
|
65
58
|
};
|
|
66
59
|
|
|
67
60
|
const skipDirName = (name) => name === '.git' || SKIP_DIRS.includes(name);
|
|
68
61
|
|
|
69
|
-
const closeWatcher = (watcher) => {
|
|
70
|
-
try {
|
|
71
|
-
watcher.close();
|
|
72
|
-
} catch {
|
|
73
|
-
// already closed
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
62
|
const reviewMarkdown = (rel) => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const rest = norm.slice('.review/'.length);
|
|
63
|
+
if (!rel.startsWith('.review/')) return false;
|
|
64
|
+
const rest = rel.slice('.review/'.length);
|
|
81
65
|
if (!rest || rest.includes('/')) return false;
|
|
82
66
|
return rest.endsWith('.md');
|
|
83
67
|
};
|
|
84
68
|
|
|
85
69
|
const isReviewDir = (root, dir) => {
|
|
86
|
-
const rel = path.relative(root, dir)
|
|
70
|
+
const rel = slashRel(path.relative(root, dir));
|
|
87
71
|
return rel === '.review' || rel.startsWith('.review/');
|
|
88
72
|
};
|
|
89
73
|
|
|
@@ -106,16 +90,15 @@ const isBareReviewName = (root, dir, rel) => {
|
|
|
106
90
|
const isReviewEvent = (root, dir, name) => {
|
|
107
91
|
if (isReviewDir(root, dir)) return true;
|
|
108
92
|
if (!name) return false;
|
|
109
|
-
const rel = path.relative(root, path.join(dir, name));
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return isBareReviewName(root, dir, norm);
|
|
93
|
+
const rel = slashRel(path.relative(root, path.join(dir, name)));
|
|
94
|
+
if (reviewMarkdown(rel)) return true;
|
|
95
|
+
return isBareReviewName(root, dir, rel);
|
|
113
96
|
};
|
|
114
97
|
|
|
115
98
|
const isOwnDirEvent = (dir, name) => {
|
|
116
99
|
if (!name) return false;
|
|
117
100
|
const base = path.basename(dir);
|
|
118
|
-
const slash =
|
|
101
|
+
const slash = slashRel(name);
|
|
119
102
|
const bare = slash.startsWith('./') ? slash.slice(2) : slash;
|
|
120
103
|
const trimmed = bare.endsWith('/') ? bare.slice(0, -1) : bare;
|
|
121
104
|
if (trimmed === base) {
|
|
@@ -144,200 +127,201 @@ const unchangedSince = (full, since) => {
|
|
|
144
127
|
}
|
|
145
128
|
};
|
|
146
129
|
|
|
147
|
-
const schedule = (state, timerKey, fire) => {
|
|
148
|
-
if (state.closed || !fire) return;
|
|
149
|
-
if (state[timerKey] !== null) clearTimeout(state[timerKey]);
|
|
150
|
-
state[timerKey] = setTimeout(() => {
|
|
151
|
-
state[timerKey] = null;
|
|
152
|
-
if (state.closed) return;
|
|
153
|
-
fire();
|
|
154
|
-
}, state.debounceMs);
|
|
155
|
-
const timer = state[timerKey];
|
|
156
|
-
if (timer && typeof timer.unref === 'function') timer.unref();
|
|
157
|
-
};
|
|
158
|
-
|
|
159
130
|
const REVIEW_HOLD_MS = 200;
|
|
160
131
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
132
|
+
class DiskWatcher {
|
|
133
|
+
constructor(options) {
|
|
134
|
+
this.root = path.resolve(options.root);
|
|
135
|
+
this.debounceMs = options.debounceMs ?? DEBOUNCE_MS;
|
|
136
|
+
this.onChange = options.onChange;
|
|
137
|
+
this.onReview = options.onReview;
|
|
138
|
+
this.onPaths = options.onPaths;
|
|
139
|
+
this.recursive = options.recursive ?? canWatchRecursive();
|
|
140
|
+
this.watchers = [];
|
|
141
|
+
this.watched = new Set();
|
|
142
|
+
this.files = new Set();
|
|
143
|
+
this.pending = new Set();
|
|
144
|
+
this.timers = { change: null, review: null, loose: null, paths: null };
|
|
145
|
+
this.looseChange = false;
|
|
146
|
+
this.reviewSeenAt = 0;
|
|
147
|
+
this.startedAt = Date.now();
|
|
148
|
+
this.closed = false;
|
|
149
|
+
const scopes = options.paths?.length ? options.paths : ['.'];
|
|
150
|
+
for (const spec of scopes) this.watchScope(spec);
|
|
151
|
+
const gitDir = path.resolve(this.root, '.git');
|
|
152
|
+
this.watchOne(gitDir);
|
|
153
|
+
this.watchOne(path.join(gitDir, 'refs'));
|
|
154
|
+
this.watchOne(path.join(gitDir, 'logs'));
|
|
155
|
+
this.watchOne(path.resolve(this.root, runs.runsDir('.')));
|
|
156
|
+
this.watchOne(path.resolve(this.root, '.review'));
|
|
157
|
+
}
|
|
167
158
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
};
|
|
159
|
+
schedule(key, fire) {
|
|
160
|
+
if (this.closed || !fire) return;
|
|
161
|
+
this.clearTimer(key);
|
|
162
|
+
this.timers[key] = setTimeout(() => {
|
|
163
|
+
this.timers[key] = null;
|
|
164
|
+
if (!this.closed) fire();
|
|
165
|
+
}, this.debounceMs);
|
|
166
|
+
this.timers[key].unref();
|
|
167
|
+
}
|
|
175
168
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
});
|
|
181
|
-
};
|
|
169
|
+
clearTimer(key) {
|
|
170
|
+
if (this.timers[key] !== null) clearTimeout(this.timers[key]);
|
|
171
|
+
this.timers[key] = null;
|
|
172
|
+
}
|
|
182
173
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
174
|
+
reviewBurst() {
|
|
175
|
+
if (!this.reviewSeenAt) return false;
|
|
176
|
+
const hold = Math.max(this.debounceMs * 2, REVIEW_HOLD_MS);
|
|
177
|
+
return Date.now() - this.reviewSeenAt < hold;
|
|
178
|
+
}
|
|
187
179
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
180
|
+
flushPaths() {
|
|
181
|
+
if (!this.pending.size) return;
|
|
182
|
+
const list = [...this.pending];
|
|
183
|
+
this.pending.clear();
|
|
184
|
+
if (this.onPaths) this.onPaths(list);
|
|
185
|
+
}
|
|
192
186
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
state.reviewSeenAt = Date.now();
|
|
202
|
-
dropLooseChange(state);
|
|
203
|
-
schedule(state, 'reviewTimer', state.onReview);
|
|
204
|
-
if (!wanted) return;
|
|
187
|
+
scheduleChange(loose = false) {
|
|
188
|
+
const idle = this.timers.change === null;
|
|
189
|
+
this.looseChange = loose && (idle || this.looseChange);
|
|
190
|
+
this.schedule('change', () => {
|
|
191
|
+
if (this.looseChange && this.reviewBurst()) return;
|
|
192
|
+
this.flushPaths();
|
|
193
|
+
if (this.onChange) this.onChange();
|
|
194
|
+
});
|
|
205
195
|
}
|
|
206
|
-
if (!name) return void scheduleUnnamed(state);
|
|
207
|
-
if (!wanted && ignoredRel(rel)) return;
|
|
208
|
-
if (isOwnDirEvent(dir, name)) return;
|
|
209
|
-
const full = path.join(dir, name);
|
|
210
|
-
if (unchangedSince(full, state.startedAt)) return;
|
|
211
|
-
if (eventType === 'rename') state.watchNewDir(full);
|
|
212
|
-
scheduleChange(state);
|
|
213
|
-
};
|
|
214
196
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
};
|
|
222
|
-
const watcher = fs.watch(
|
|
223
|
-
target,
|
|
224
|
-
{ persistent: false, encoding: 'utf8', ...extra },
|
|
225
|
-
onEvent,
|
|
226
|
-
);
|
|
227
|
-
if (typeof watcher.on === 'function') {
|
|
228
|
-
watcher.on('error', () => {});
|
|
229
|
-
}
|
|
230
|
-
state.watched.add(target);
|
|
231
|
-
state.watchers.push(watcher);
|
|
232
|
-
} catch {
|
|
233
|
-
// missing path or too many watchers
|
|
197
|
+
scheduleUnnamed() {
|
|
198
|
+
if (this.reviewBurst()) return;
|
|
199
|
+
this.pending.add(UNKNOWN_PATH);
|
|
200
|
+
this.schedule('loose', () => {
|
|
201
|
+
if (!this.reviewBurst()) this.scheduleChange(true);
|
|
202
|
+
});
|
|
234
203
|
}
|
|
235
|
-
};
|
|
236
204
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
let entries;
|
|
241
|
-
try {
|
|
242
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
243
|
-
} catch {
|
|
244
|
-
return;
|
|
205
|
+
dropLooseChange() {
|
|
206
|
+
this.clearTimer('loose');
|
|
207
|
+
if (this.looseChange) this.clearTimer('change');
|
|
245
208
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (
|
|
249
|
-
|
|
209
|
+
|
|
210
|
+
onEvent(dir, eventType, filename) {
|
|
211
|
+
if (this.closed) return;
|
|
212
|
+
const name = filename ? `${filename}` : '';
|
|
213
|
+
const rel = name
|
|
214
|
+
? slashRel(path.relative(this.root, path.join(dir, name)))
|
|
215
|
+
: '';
|
|
216
|
+
const wanted = this.files.has(rel);
|
|
217
|
+
if (isRunsRel(rel)) {
|
|
218
|
+
this.pending.add(rel);
|
|
219
|
+
if (name && eventType === 'rename') {
|
|
220
|
+
this.watchNewDir(path.join(dir, name));
|
|
221
|
+
}
|
|
222
|
+
return void this.schedule('paths', () => this.flushPaths());
|
|
223
|
+
}
|
|
224
|
+
if (isReviewEvent(this.root, dir, name)) {
|
|
225
|
+
this.reviewSeenAt = Date.now();
|
|
226
|
+
this.dropLooseChange();
|
|
227
|
+
this.schedule('review', this.onReview);
|
|
228
|
+
if (!wanted) return;
|
|
229
|
+
}
|
|
230
|
+
if (!name) return void this.scheduleUnnamed();
|
|
231
|
+
if (!wanted && ignoredRel(rel)) return;
|
|
232
|
+
if (isOwnDirEvent(dir, name)) return;
|
|
233
|
+
const full = path.join(dir, name);
|
|
234
|
+
if (unchangedSince(full, this.startedAt)) return;
|
|
235
|
+
if (eventType === 'rename') this.watchNewDir(full);
|
|
236
|
+
this.pending.add(rel);
|
|
237
|
+
this.scheduleChange();
|
|
250
238
|
}
|
|
251
|
-
};
|
|
252
239
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
240
|
+
watchOne(target, recursive = false) {
|
|
241
|
+
if (this.closed || this.watched.has(target)) return;
|
|
242
|
+
try {
|
|
243
|
+
const options = { persistent: false, encoding: 'utf8', recursive };
|
|
244
|
+
const watcher = fs.watch(target, options, (eventType, filename) => {
|
|
245
|
+
this.onEvent(target, eventType, filename);
|
|
246
|
+
});
|
|
247
|
+
watcher.on('error', () => {});
|
|
248
|
+
this.watched.add(target);
|
|
249
|
+
this.watchers.push(watcher);
|
|
250
|
+
} catch {
|
|
251
|
+
// missing path or too many watchers
|
|
252
|
+
}
|
|
260
253
|
}
|
|
261
|
-
if (!stat.isDirectory()) return;
|
|
262
|
-
if (path.basename(full) === '.review') return void watchOne(state, full);
|
|
263
|
-
if (skipDirName(path.basename(full))) return;
|
|
264
|
-
watchTree(state, full);
|
|
265
|
-
};
|
|
266
254
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
255
|
+
watchTree(dir) {
|
|
256
|
+
this.watchOne(dir, this.recursive);
|
|
257
|
+
if (this.recursive) return;
|
|
258
|
+
let entries;
|
|
259
|
+
try {
|
|
260
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
261
|
+
} catch {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
for (const entry of entries) {
|
|
265
|
+
if (!entry.isDirectory() || skipDirName(entry.name)) continue;
|
|
266
|
+
this.watchTree(path.join(dir, entry.name));
|
|
267
|
+
}
|
|
274
268
|
}
|
|
275
|
-
if (stat.isDirectory()) return void watchTree(state, target);
|
|
276
|
-
watchOne(state, path.dirname(target));
|
|
277
|
-
};
|
|
278
269
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
270
|
+
watchNewDir(full) {
|
|
271
|
+
if (this.recursive) return;
|
|
272
|
+
try {
|
|
273
|
+
if (!fs.statSync(full).isDirectory()) return;
|
|
274
|
+
} catch {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const name = path.basename(full);
|
|
278
|
+
if (name === '.review') this.watchOne(full);
|
|
279
|
+
else if (!skipDirName(name)) this.watchTree(full);
|
|
280
|
+
}
|
|
285
281
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
282
|
+
watchScope(spec) {
|
|
283
|
+
const target = path.resolve(this.root, spec);
|
|
284
|
+
try {
|
|
285
|
+
if (fs.statSync(target).isDirectory()) return void this.watchTree(target);
|
|
286
|
+
} catch {
|
|
287
|
+
// watch the parent until the path appears
|
|
288
|
+
}
|
|
289
|
+
this.watchOne(path.dirname(target));
|
|
290
|
+
}
|
|
294
291
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
292
|
+
watchFiles(rels) {
|
|
293
|
+
this.files = new Set();
|
|
294
|
+
for (const rel of rels) {
|
|
295
|
+
if (!rel) continue;
|
|
296
|
+
const full = path.resolve(this.root, rel);
|
|
297
|
+
this.files.add(slashRel(path.relative(this.root, full)));
|
|
298
|
+
this.watchOne(path.dirname(full));
|
|
299
|
+
}
|
|
302
300
|
}
|
|
303
|
-
};
|
|
304
301
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
looseChange: false,
|
|
321
|
-
reviewSeenAt: 0,
|
|
322
|
-
startedAt: Date.now(),
|
|
323
|
-
closed: false,
|
|
324
|
-
watchNewDir: (full) => maybeWatchNewDir(state, full),
|
|
325
|
-
};
|
|
326
|
-
const scopes = options.paths && options.paths.length ? options.paths : ['.'];
|
|
327
|
-
for (const spec of scopes) watchScope(state, spec);
|
|
328
|
-
watchGit(state);
|
|
329
|
-
watchOne(state, path.resolve(state.root, '.review'));
|
|
330
|
-
return {
|
|
331
|
-
close: () => stopState(state),
|
|
332
|
-
watchFiles: (rels) => watchFiles(state, rels),
|
|
333
|
-
};
|
|
334
|
-
};
|
|
302
|
+
close() {
|
|
303
|
+
this.closed = true;
|
|
304
|
+
for (const key of Object.keys(this.timers)) this.clearTimer(key);
|
|
305
|
+
this.pending.clear();
|
|
306
|
+
for (const watcher of this.watchers) {
|
|
307
|
+
try {
|
|
308
|
+
watcher.close();
|
|
309
|
+
} catch {
|
|
310
|
+
// already closed
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
this.watchers = [];
|
|
314
|
+
this.watched.clear();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
335
317
|
|
|
336
318
|
module.exports = {
|
|
337
319
|
DEBOUNCE_MS,
|
|
320
|
+
UNKNOWN_PATH,
|
|
321
|
+
MODULES_STAMP,
|
|
338
322
|
canWatchRecursive,
|
|
339
323
|
ignoredRel,
|
|
340
324
|
isOwnDirEvent,
|
|
341
325
|
unchangedSince,
|
|
342
|
-
|
|
326
|
+
DiskWatcher,
|
|
343
327
|
};
|