reslop 0.2.4 → 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 +25 -1
- package/LICENSE +1 -1
- package/README.md +12 -13
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -12
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +48 -18
- 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 +196 -404
- package/lib/deps.js +240 -399
- 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 +138 -141
- 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 +90 -206
- package/lib/editor.js +98 -55
- package/lib/files.js +86 -103
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +182 -344
- 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 +157 -132
- 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 +16 -26
- 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 +22 -35
- package/lib/highlight/txt.js +9 -22
- package/lib/highlight.js +17 -46
- package/lib/keys.js +62 -85
- package/lib/manifest.js +67 -130
- package/lib/npm-commands.js +119 -189
- package/lib/remote.js +141 -197
- package/lib/render/branches.js +66 -73
- package/lib/render/chrome.js +264 -323
- package/lib/render/commits.js +187 -500
- 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 -228
- package/lib/render/files.js +45 -99
- package/lib/render/frame.js +129 -183
- package/lib/render/notes.js +144 -160
- package/lib/render/npm.js +234 -112
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +131 -170
- 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 -28
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -38
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -78
- package/lib/report-test.js +256 -141
- package/lib/report-tools.js +96 -161
- package/lib/review-merge.js +114 -152
- package/lib/review.js +115 -189
- package/lib/runs.js +225 -0
- package/lib/select.js +89 -75
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +82 -63
- package/lib/session/branches.js +193 -247
- package/lib/session/change-actions.js +171 -214
- package/lib/session/commit.js +280 -342
- package/lib/session/compose.js +559 -674
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +164 -157
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +85 -53
- package/lib/session/items.js +73 -104
- package/lib/session/lifecycle.js +403 -541
- package/lib/session/load.js +48 -68
- package/lib/session/navigation.js +96 -87
- package/lib/session/npm.js +409 -345
- package/lib/session/ops.js +196 -63
- package/lib/session/pointer.js +23 -15
- package/lib/session/progress.js +33 -21
- package/lib/session/review.js +33 -54
- package/lib/session/tasks.js +333 -0
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -136
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -97
- package/lib/session/view.js +52 -83
- package/lib/session/watch.js +208 -204
- package/lib/session.js +112 -237
- package/lib/update.js +45 -116
- package/lib/utilities.js +67 -89
- package/lib/wrap.js +33 -44
- package/package.json +1 -1
- package/lib/session/todos.js +0 -293
package/lib/session/watch.js
CHANGED
|
@@ -3,8 +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;
|
|
7
|
-
const
|
|
10
|
+
const UNKNOWN_PATH = '.';
|
|
11
|
+
const MODULES_STAMP = 'node_modules/.package-lock.json';
|
|
8
12
|
|
|
9
13
|
const SKIP_DIRS = ['node_modules', '.review', 'coverage', 'dist', '.cache'];
|
|
10
14
|
|
|
@@ -15,73 +19,55 @@ const GIT_WATCH_NAMES = [
|
|
|
15
19
|
'FETCH_HEAD',
|
|
16
20
|
'ORIG_HEAD',
|
|
17
21
|
'refs',
|
|
22
|
+
'rebase-merge',
|
|
23
|
+
'rebase-apply',
|
|
18
24
|
];
|
|
19
25
|
|
|
20
|
-
const linuxRecursiveNode = (version) => {
|
|
21
|
-
const parts = `${version}`.split('.');
|
|
22
|
-
const major = Number(parts[0]);
|
|
23
|
-
const minor = Number(parts[1]);
|
|
24
|
-
if (major > 19) return true;
|
|
25
|
-
return major === 19 && minor >= 1;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
26
|
const canWatchRecursive = (
|
|
29
27
|
platform = process.platform,
|
|
30
28
|
version = process.versions.node,
|
|
31
29
|
) => {
|
|
32
30
|
if (platform === 'win32' || platform === 'darwin') return true;
|
|
33
|
-
if (platform
|
|
34
|
-
|
|
31
|
+
if (platform !== 'linux') return false;
|
|
32
|
+
const [major, minor] = `${version}`.split('.').map(Number);
|
|
33
|
+
return major > 19 || (major === 19 && minor >= 1);
|
|
35
34
|
};
|
|
36
35
|
|
|
37
|
-
const
|
|
38
|
-
if (!name) return false;
|
|
39
|
-
if (name.endsWith('.lock')) return true;
|
|
40
|
-
if (name.endsWith('~')) return true;
|
|
41
|
-
if (name.endsWith('.swp') || name.endsWith('.swo')) return true;
|
|
42
|
-
if (name.startsWith('.#')) return true;
|
|
43
|
-
if (name === '.DS_Store') return true;
|
|
44
|
-
return false;
|
|
45
|
-
};
|
|
36
|
+
const IGNORED_SUFFIXES = ['.lock', '~', '.swp', '.swo'];
|
|
46
37
|
|
|
47
|
-
const
|
|
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
|
|
|
48
|
+
const slashRel = (rel) => `${rel}`.replaceAll('\\', '/');
|
|
49
|
+
|
|
54
50
|
const ignoredRel = (rel) => {
|
|
55
|
-
const norm =
|
|
51
|
+
const norm = slashRel(rel);
|
|
56
52
|
if (!norm || norm === '.') return false;
|
|
53
|
+
if (norm === MODULES_STAMP) return false;
|
|
57
54
|
const parts = norm.split('/');
|
|
58
|
-
|
|
59
|
-
if (SKIP_DIRS.includes(part)) return true;
|
|
60
|
-
}
|
|
55
|
+
if (parts.some((part) => SKIP_DIRS.includes(part))) return true;
|
|
61
56
|
if (parts[0] === '.git') return ignoredGitRel(parts);
|
|
62
57
|
return ignoredName(parts[parts.length - 1]);
|
|
63
58
|
};
|
|
64
59
|
|
|
65
60
|
const skipDirName = (name) => name === '.git' || SKIP_DIRS.includes(name);
|
|
66
61
|
|
|
67
|
-
const closeWatcher = (watcher) => {
|
|
68
|
-
try {
|
|
69
|
-
watcher.close();
|
|
70
|
-
} catch {
|
|
71
|
-
// already closed
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
|
|
75
62
|
const reviewMarkdown = (rel) => {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const rest = norm.slice('.review/'.length);
|
|
63
|
+
if (!rel.startsWith('.review/')) return false;
|
|
64
|
+
const rest = rel.slice('.review/'.length);
|
|
79
65
|
if (!rest || rest.includes('/')) return false;
|
|
80
66
|
return rest.endsWith('.md');
|
|
81
67
|
};
|
|
82
68
|
|
|
83
69
|
const isReviewDir = (root, dir) => {
|
|
84
|
-
const rel = path.relative(root, dir)
|
|
70
|
+
const rel = slashRel(path.relative(root, dir));
|
|
85
71
|
return rel === '.review' || rel.startsWith('.review/');
|
|
86
72
|
};
|
|
87
73
|
|
|
@@ -95,7 +81,7 @@ const hasFile = (full) => {
|
|
|
95
81
|
};
|
|
96
82
|
|
|
97
83
|
const isBareReviewName = (root, dir, rel) => {
|
|
98
|
-
if (!rel || rel.includes('/')
|
|
84
|
+
if (!rel || rel.includes('/')) return false;
|
|
99
85
|
const base = path.basename(rel);
|
|
100
86
|
if (hasFile(path.join(dir, base))) return false;
|
|
101
87
|
return hasFile(path.join(root, '.review', base));
|
|
@@ -104,16 +90,15 @@ const isBareReviewName = (root, dir, rel) => {
|
|
|
104
90
|
const isReviewEvent = (root, dir, name) => {
|
|
105
91
|
if (isReviewDir(root, dir)) return true;
|
|
106
92
|
if (!name) return false;
|
|
107
|
-
const rel = path.relative(root, path.join(dir, name));
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
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);
|
|
111
96
|
};
|
|
112
97
|
|
|
113
98
|
const isOwnDirEvent = (dir, name) => {
|
|
114
99
|
if (!name) return false;
|
|
115
100
|
const base = path.basename(dir);
|
|
116
|
-
const slash =
|
|
101
|
+
const slash = slashRel(name);
|
|
117
102
|
const bare = slash.startsWith('./') ? slash.slice(2) : slash;
|
|
118
103
|
const trimmed = bare.endsWith('/') ? bare.slice(0, -1) : bare;
|
|
119
104
|
if (trimmed === base) {
|
|
@@ -133,191 +118,210 @@ const isOwnDirEvent = (dir, name) => {
|
|
|
133
118
|
}
|
|
134
119
|
};
|
|
135
120
|
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}, state.debounceMs);
|
|
144
|
-
const timer = state[timerKey];
|
|
145
|
-
if (timer && typeof timer.unref === 'function') timer.unref();
|
|
121
|
+
const unchangedSince = (full, since) => {
|
|
122
|
+
try {
|
|
123
|
+
const stat = fs.statSync(full);
|
|
124
|
+
return Math.max(stat.mtimeMs, stat.ctimeMs) < since;
|
|
125
|
+
} catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
146
128
|
};
|
|
147
129
|
|
|
148
130
|
const REVIEW_HOLD_MS = 200;
|
|
149
131
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
+
}
|
|
156
158
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
+
}
|
|
163
168
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
scheduleChange(state);
|
|
169
|
-
});
|
|
170
|
-
};
|
|
169
|
+
clearTimer(key) {
|
|
170
|
+
if (this.timers[key] !== null) clearTimeout(this.timers[key]);
|
|
171
|
+
this.timers[key] = null;
|
|
172
|
+
}
|
|
171
173
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
};
|
|
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
|
+
}
|
|
178
179
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
state.reviewSeenAt = Date.now();
|
|
185
|
-
dropChange(state);
|
|
186
|
-
return void schedule(state, 'reviewTimer', state.onReview);
|
|
180
|
+
flushPaths() {
|
|
181
|
+
if (!this.pending.size) return;
|
|
182
|
+
const list = [...this.pending];
|
|
183
|
+
this.pending.clear();
|
|
184
|
+
if (this.onPaths) this.onPaths(list);
|
|
187
185
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
|
|
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
|
+
});
|
|
194
195
|
}
|
|
195
|
-
scheduleChange(state);
|
|
196
|
-
};
|
|
197
196
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
};
|
|
205
|
-
const watcher = fs.watch(
|
|
206
|
-
target,
|
|
207
|
-
{ persistent: false, encoding: 'utf8', ...extra },
|
|
208
|
-
onEvent,
|
|
209
|
-
);
|
|
210
|
-
if (typeof watcher.on === 'function') {
|
|
211
|
-
watcher.on('error', () => {});
|
|
212
|
-
}
|
|
213
|
-
state.watched.add(target);
|
|
214
|
-
state.watchers.push(watcher);
|
|
215
|
-
} catch {
|
|
216
|
-
// 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
|
+
});
|
|
217
203
|
}
|
|
218
|
-
};
|
|
219
204
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
let entries;
|
|
224
|
-
try {
|
|
225
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
226
|
-
} catch {
|
|
227
|
-
return;
|
|
205
|
+
dropLooseChange() {
|
|
206
|
+
this.clearTimer('loose');
|
|
207
|
+
if (this.looseChange) this.clearTimer('change');
|
|
228
208
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
|
|
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();
|
|
233
238
|
}
|
|
234
|
-
};
|
|
235
239
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
+
}
|
|
243
253
|
}
|
|
244
|
-
if (!stat.isDirectory()) return;
|
|
245
|
-
if (path.basename(full) === '.review') return void watchOne(state, full);
|
|
246
|
-
if (skipDirName(path.basename(full))) return;
|
|
247
|
-
watchTree(state, full);
|
|
248
|
-
};
|
|
249
254
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
+
}
|
|
257
268
|
}
|
|
258
|
-
if (stat.isDirectory()) return void watchTree(state, target);
|
|
259
|
-
watchOne(state, path.dirname(target));
|
|
260
|
-
};
|
|
261
269
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
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
|
+
}
|
|
267
281
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
state.watched.clear();
|
|
278
|
-
};
|
|
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
|
+
}
|
|
279
291
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
+
}
|
|
285
300
|
}
|
|
286
|
-
};
|
|
287
301
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
closed: false,
|
|
304
|
-
watchNewDir: (full) => maybeWatchNewDir(state, full),
|
|
305
|
-
};
|
|
306
|
-
const scopes = options.paths && options.paths.length ? options.paths : ['.'];
|
|
307
|
-
for (const spec of scopes) watchScope(state, spec);
|
|
308
|
-
watchGit(state);
|
|
309
|
-
watchOne(state, path.resolve(state.root, '.review'));
|
|
310
|
-
return {
|
|
311
|
-
close: () => stopState(state),
|
|
312
|
-
watchFiles: (rels) => watchFiles(state, rels),
|
|
313
|
-
};
|
|
314
|
-
};
|
|
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
|
+
}
|
|
315
317
|
|
|
316
318
|
module.exports = {
|
|
317
319
|
DEBOUNCE_MS,
|
|
318
|
-
|
|
320
|
+
UNKNOWN_PATH,
|
|
321
|
+
MODULES_STAMP,
|
|
319
322
|
canWatchRecursive,
|
|
320
323
|
ignoredRel,
|
|
321
324
|
isOwnDirEvent,
|
|
322
|
-
|
|
325
|
+
unchangedSince,
|
|
326
|
+
DiskWatcher,
|
|
323
327
|
};
|