source: node_modules/rollup/dist/shared/watch.js@ 57e58a3

Last change on this file since 57e58a3 was 57e58a3, checked in by ste08 <sjovanoska@…>, 4 months ago

Initial commit

  • Property mode set to 100644
File size: 10.3 KB
Line 
1/*
2 @license
3 Rollup.js v4.34.4
4 Wed, 05 Feb 2025 21:30:40 GMT - commit 19312a762c3cda56a0f6dc80a0887a4499db2257
5
6 https://github.com/rollup/rollup
7
8 Released under the MIT License.
9*/
10'use strict';
11
12Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
13
14const rollup = require('./rollup.js');
15const path = require('node:path');
16const process = require('node:process');
17const index = require('./index.js');
18const node_os = require('node:os');
19require('./parseAst.js');
20require('../native.js');
21require('path');
22require('node:perf_hooks');
23require('node:fs/promises');
24require('util');
25require('fs');
26require('stream');
27require('os');
28require('./fsevents-importer.js');
29require('events');
30
31class FileWatcher {
32 constructor(task, chokidarOptions) {
33 this.transformWatchers = new Map();
34 this.chokidarOptions = chokidarOptions;
35 this.task = task;
36 this.watcher = this.createWatcher(null);
37 }
38 close() {
39 this.watcher.close();
40 for (const watcher of this.transformWatchers.values()) {
41 watcher.close();
42 }
43 }
44 unwatch(id) {
45 this.watcher.unwatch(id);
46 const transformWatcher = this.transformWatchers.get(id);
47 if (transformWatcher) {
48 this.transformWatchers.delete(id);
49 transformWatcher.close();
50 }
51 }
52 watch(id, isTransformDependency) {
53 if (isTransformDependency) {
54 const watcher = this.transformWatchers.get(id) ?? this.createWatcher(id);
55 watcher.add(id);
56 this.transformWatchers.set(id, watcher);
57 }
58 else {
59 this.watcher.add(id);
60 }
61 }
62 createWatcher(transformWatcherId) {
63 const task = this.task;
64 const isLinux = node_os.platform() === 'linux';
65 const isFreeBSD = node_os.platform() === 'freebsd';
66 const isTransformDependency = transformWatcherId !== null;
67 const handleChange = (id, event) => {
68 const changedId = transformWatcherId || id;
69 if (isLinux || isFreeBSD) {
70 // unwatching and watching fixes an issue with chokidar where on certain systems,
71 // a file that was unlinked and immediately recreated would create a change event
72 // but then no longer any further events
73 watcher.unwatch(changedId);
74 watcher.add(changedId);
75 }
76 task.invalidate(changedId, { event, isTransformDependency });
77 };
78 const watcher = index.chokidar
79 .watch([], this.chokidarOptions)
80 .on('add', id => handleChange(id, 'create'))
81 .on('change', id => handleChange(id, 'update'))
82 .on('unlink', id => handleChange(id, 'delete'));
83 return watcher;
84 }
85}
86
87const eventsRewrites = {
88 create: {
89 create: 'buggy',
90 delete: null, //delete file from map
91 update: 'create'
92 },
93 delete: {
94 create: 'update',
95 delete: 'buggy',
96 update: 'buggy'
97 },
98 update: {
99 create: 'buggy',
100 delete: 'delete',
101 update: 'update'
102 }
103};
104class Watcher {
105 constructor(optionsList, emitter) {
106 this.buildDelay = 0;
107 this.buildTimeout = null;
108 this.closed = false;
109 this.invalidatedIds = new Map();
110 this.rerun = false;
111 this.running = true;
112 this.emitter = emitter;
113 emitter.close = this.close.bind(this);
114 this.tasks = optionsList.map(options => new Task(this, options));
115 for (const { watch } of optionsList) {
116 if (watch && typeof watch.buildDelay === 'number') {
117 this.buildDelay = Math.max(this.buildDelay, watch.buildDelay);
118 }
119 }
120 process.nextTick(() => this.run());
121 }
122 async close() {
123 if (this.closed)
124 return;
125 this.closed = true;
126 if (this.buildTimeout)
127 clearTimeout(this.buildTimeout);
128 for (const task of this.tasks) {
129 task.close();
130 }
131 await this.emitter.emit('close');
132 this.emitter.removeAllListeners();
133 }
134 invalidate(file) {
135 if (file) {
136 const previousEvent = this.invalidatedIds.get(file.id);
137 const event = previousEvent ? eventsRewrites[previousEvent][file.event] : file.event;
138 if (event === 'buggy') {
139 //TODO: throws or warn? Currently just ignore, uses new event
140 this.invalidatedIds.set(file.id, file.event);
141 }
142 else if (event === null) {
143 this.invalidatedIds.delete(file.id);
144 }
145 else {
146 this.invalidatedIds.set(file.id, event);
147 }
148 }
149 if (this.running) {
150 this.rerun = true;
151 return;
152 }
153 if (this.buildTimeout)
154 clearTimeout(this.buildTimeout);
155 this.buildTimeout = setTimeout(async () => {
156 this.buildTimeout = null;
157 try {
158 await Promise.all([...this.invalidatedIds].map(([id, event]) => this.emitter.emit('change', id, { event })));
159 this.invalidatedIds.clear();
160 await this.emitter.emit('restart');
161 this.emitter.removeListenersForCurrentRun();
162 this.run();
163 }
164 catch (error) {
165 this.invalidatedIds.clear();
166 await this.emitter.emit('event', {
167 code: 'ERROR',
168 error,
169 result: null
170 });
171 await this.emitter.emit('event', {
172 code: 'END'
173 });
174 }
175 }, this.buildDelay);
176 }
177 async run() {
178 this.running = true;
179 await this.emitter.emit('event', {
180 code: 'START'
181 });
182 for (const task of this.tasks) {
183 await task.run();
184 }
185 this.running = false;
186 await this.emitter.emit('event', {
187 code: 'END'
188 });
189 if (this.rerun) {
190 this.rerun = false;
191 this.invalidate();
192 }
193 }
194}
195class Task {
196 constructor(watcher, options) {
197 this.cache = { modules: [] };
198 this.watchFiles = [];
199 this.closed = false;
200 this.invalidated = true;
201 this.watched = new Set();
202 this.watcher = watcher;
203 this.options = options;
204 this.skipWrite = Boolean(options.watch && options.watch.skipWrite);
205 this.outputs = this.options.output;
206 this.outputFiles = this.outputs.map(output => {
207 if (output.file || output.dir)
208 return path.resolve(output.file || output.dir);
209 return undefined;
210 });
211 this.watchOptions = this.options.watch || {};
212 this.filter = rollup.createFilter(this.watchOptions.include, this.watchOptions.exclude);
213 this.fileWatcher = new FileWatcher(this, {
214 ...this.watchOptions.chokidar,
215 disableGlobbing: true,
216 ignoreInitial: true
217 });
218 }
219 close() {
220 this.closed = true;
221 this.fileWatcher.close();
222 }
223 invalidate(id, details) {
224 this.invalidated = true;
225 if (details.isTransformDependency) {
226 for (const module of this.cache.modules) {
227 if (!module.transformDependencies.includes(id))
228 continue;
229 // effective invalidation
230 module.originalCode = null;
231 }
232 }
233 this.watcher.invalidate({ event: details.event, id });
234 this.watchOptions.onInvalidate?.(id);
235 }
236 async run() {
237 if (!this.invalidated)
238 return;
239 this.invalidated = false;
240 const options = {
241 ...this.options,
242 cache: this.cache
243 };
244 const start = Date.now();
245 await this.watcher.emitter.emit('event', {
246 code: 'BUNDLE_START',
247 input: this.options.input,
248 output: this.outputFiles
249 });
250 let result = null;
251 try {
252 result = await rollup.rollupInternal(options, this.watcher.emitter);
253 if (this.closed) {
254 return;
255 }
256 this.updateWatchedFiles(result);
257 if (!this.skipWrite) {
258 await Promise.all(this.outputs.map(output => result.write(output)));
259 if (this.closed) {
260 return;
261 }
262 this.updateWatchedFiles(result);
263 }
264 await this.watcher.emitter.emit('event', {
265 code: 'BUNDLE_END',
266 duration: Date.now() - start,
267 input: this.options.input,
268 output: this.outputFiles,
269 result
270 });
271 }
272 catch (error) {
273 if (!this.closed) {
274 if (Array.isArray(error.watchFiles)) {
275 for (const id of error.watchFiles) {
276 this.watchFile(id);
277 }
278 }
279 if (error.id) {
280 this.cache.modules = this.cache.modules.filter(module => module.id !== error.id);
281 }
282 }
283 await this.watcher.emitter.emit('event', {
284 code: 'ERROR',
285 error,
286 result
287 });
288 }
289 }
290 updateWatchedFiles(result) {
291 const previouslyWatched = this.watched;
292 this.watched = new Set();
293 this.watchFiles = result.watchFiles;
294 this.cache = result.cache;
295 for (const id of this.watchFiles) {
296 this.watchFile(id);
297 }
298 for (const module of this.cache.modules) {
299 for (const depId of module.transformDependencies) {
300 this.watchFile(depId, true);
301 }
302 }
303 for (const id of previouslyWatched) {
304 if (!this.watched.has(id)) {
305 this.fileWatcher.unwatch(id);
306 }
307 }
308 }
309 watchFile(id, isTransformDependency = false) {
310 if (!this.filter(id))
311 return;
312 this.watched.add(id);
313 if (this.outputFiles.includes(id)) {
314 throw new Error('Cannot import the generated bundle');
315 }
316 // this is necessary to ensure that any 'renamed' files
317 // continue to be watched following an error
318 this.fileWatcher.watch(id, isTransformDependency);
319 }
320}
321
322exports.Task = Task;
323exports.Watcher = Watcher;
324//# sourceMappingURL=watch.js.map
Note: See TracBrowser for help on using the repository browser.