watch.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /*
  2. @license
  3. Rollup.js v2.40.0
  4. Fri, 26 Feb 2021 14:39:44 GMT - commit 0a0958ff926554abe9916178f56762ba71301ddd
  5. https://github.com/rollup/rollup
  6. Released under the MIT License.
  7. */
  8. 'use strict';
  9. var path = require('path');
  10. var require$$0 = require('util');
  11. var index = require('./index.js');
  12. var rollup = require('./rollup.js');
  13. var mergeOptions = require('./mergeOptions.js');
  14. var require$$2 = require('os');
  15. require('events');
  16. require('fs');
  17. require('stream');
  18. require('crypto');
  19. const util = require$$0;
  20. const braces = index.braces_1;
  21. const picomatch = index.picomatch;
  22. const utils = index.utils;
  23. const isEmptyString = val => typeof val === 'string' && (val === '' || val === './');
  24. /**
  25. * Returns an array of strings that match one or more glob patterns.
  26. *
  27. * ```js
  28. * const mm = require('micromatch');
  29. * // mm(list, patterns[, options]);
  30. *
  31. * console.log(mm(['a.js', 'a.txt'], ['*.js']));
  32. * //=> [ 'a.js' ]
  33. * ```
  34. * @param {String|Array<string>} list List of strings to match.
  35. * @param {String|Array<string>} patterns One or more glob patterns to use for matching.
  36. * @param {Object} options See available [options](#options)
  37. * @return {Array} Returns an array of matches
  38. * @summary false
  39. * @api public
  40. */
  41. const micromatch = (list, patterns, options) => {
  42. patterns = [].concat(patterns);
  43. list = [].concat(list);
  44. let omit = new Set();
  45. let keep = new Set();
  46. let items = new Set();
  47. let negatives = 0;
  48. let onResult = state => {
  49. items.add(state.output);
  50. if (options && options.onResult) {
  51. options.onResult(state);
  52. }
  53. };
  54. for (let i = 0; i < patterns.length; i++) {
  55. let isMatch = picomatch(String(patterns[i]), { ...options, onResult }, true);
  56. let negated = isMatch.state.negated || isMatch.state.negatedExtglob;
  57. if (negated) negatives++;
  58. for (let item of list) {
  59. let matched = isMatch(item, true);
  60. let match = negated ? !matched.isMatch : matched.isMatch;
  61. if (!match) continue;
  62. if (negated) {
  63. omit.add(matched.output);
  64. } else {
  65. omit.delete(matched.output);
  66. keep.add(matched.output);
  67. }
  68. }
  69. }
  70. let result = negatives === patterns.length ? [...items] : [...keep];
  71. let matches = result.filter(item => !omit.has(item));
  72. if (options && matches.length === 0) {
  73. if (options.failglob === true) {
  74. throw new Error(`No matches found for "${patterns.join(', ')}"`);
  75. }
  76. if (options.nonull === true || options.nullglob === true) {
  77. return options.unescape ? patterns.map(p => p.replace(/\\/g, '')) : patterns;
  78. }
  79. }
  80. return matches;
  81. };
  82. /**
  83. * Backwards compatibility
  84. */
  85. micromatch.match = micromatch;
  86. /**
  87. * Returns a matcher function from the given glob `pattern` and `options`.
  88. * The returned function takes a string to match as its only argument and returns
  89. * true if the string is a match.
  90. *
  91. * ```js
  92. * const mm = require('micromatch');
  93. * // mm.matcher(pattern[, options]);
  94. *
  95. * const isMatch = mm.matcher('*.!(*a)');
  96. * console.log(isMatch('a.a')); //=> false
  97. * console.log(isMatch('a.b')); //=> true
  98. * ```
  99. * @param {String} `pattern` Glob pattern
  100. * @param {Object} `options`
  101. * @return {Function} Returns a matcher function.
  102. * @api public
  103. */
  104. micromatch.matcher = (pattern, options) => picomatch(pattern, options);
  105. /**
  106. * Returns true if **any** of the given glob `patterns` match the specified `string`.
  107. *
  108. * ```js
  109. * const mm = require('micromatch');
  110. * // mm.isMatch(string, patterns[, options]);
  111. *
  112. * console.log(mm.isMatch('a.a', ['b.*', '*.a'])); //=> true
  113. * console.log(mm.isMatch('a.a', 'b.*')); //=> false
  114. * ```
  115. * @param {String} str The string to test.
  116. * @param {String|Array} patterns One or more glob patterns to use for matching.
  117. * @param {Object} [options] See available [options](#options).
  118. * @return {Boolean} Returns true if any patterns match `str`
  119. * @api public
  120. */
  121. micromatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
  122. /**
  123. * Backwards compatibility
  124. */
  125. micromatch.any = micromatch.isMatch;
  126. /**
  127. * Returns a list of strings that _**do not match any**_ of the given `patterns`.
  128. *
  129. * ```js
  130. * const mm = require('micromatch');
  131. * // mm.not(list, patterns[, options]);
  132. *
  133. * console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a'));
  134. * //=> ['b.b', 'c.c']
  135. * ```
  136. * @param {Array} `list` Array of strings to match.
  137. * @param {String|Array} `patterns` One or more glob pattern to use for matching.
  138. * @param {Object} `options` See available [options](#options) for changing how matches are performed
  139. * @return {Array} Returns an array of strings that **do not match** the given patterns.
  140. * @api public
  141. */
  142. micromatch.not = (list, patterns, options = {}) => {
  143. patterns = [].concat(patterns).map(String);
  144. let result = new Set();
  145. let items = [];
  146. let onResult = state => {
  147. if (options.onResult) options.onResult(state);
  148. items.push(state.output);
  149. };
  150. let matches = micromatch(list, patterns, { ...options, onResult });
  151. for (let item of items) {
  152. if (!matches.includes(item)) {
  153. result.add(item);
  154. }
  155. }
  156. return [...result];
  157. };
  158. /**
  159. * Returns true if the given `string` contains the given pattern. Similar
  160. * to [.isMatch](#isMatch) but the pattern can match any part of the string.
  161. *
  162. * ```js
  163. * var mm = require('micromatch');
  164. * // mm.contains(string, pattern[, options]);
  165. *
  166. * console.log(mm.contains('aa/bb/cc', '*b'));
  167. * //=> true
  168. * console.log(mm.contains('aa/bb/cc', '*d'));
  169. * //=> false
  170. * ```
  171. * @param {String} `str` The string to match.
  172. * @param {String|Array} `patterns` Glob pattern to use for matching.
  173. * @param {Object} `options` See available [options](#options) for changing how matches are performed
  174. * @return {Boolean} Returns true if the patter matches any part of `str`.
  175. * @api public
  176. */
  177. micromatch.contains = (str, pattern, options) => {
  178. if (typeof str !== 'string') {
  179. throw new TypeError(`Expected a string: "${util.inspect(str)}"`);
  180. }
  181. if (Array.isArray(pattern)) {
  182. return pattern.some(p => micromatch.contains(str, p, options));
  183. }
  184. if (typeof pattern === 'string') {
  185. if (isEmptyString(str) || isEmptyString(pattern)) {
  186. return false;
  187. }
  188. if (str.includes(pattern) || (str.startsWith('./') && str.slice(2).includes(pattern))) {
  189. return true;
  190. }
  191. }
  192. return micromatch.isMatch(str, pattern, { ...options, contains: true });
  193. };
  194. /**
  195. * Filter the keys of the given object with the given `glob` pattern
  196. * and `options`. Does not attempt to match nested keys. If you need this feature,
  197. * use [glob-object][] instead.
  198. *
  199. * ```js
  200. * const mm = require('micromatch');
  201. * // mm.matchKeys(object, patterns[, options]);
  202. *
  203. * const obj = { aa: 'a', ab: 'b', ac: 'c' };
  204. * console.log(mm.matchKeys(obj, '*b'));
  205. * //=> { ab: 'b' }
  206. * ```
  207. * @param {Object} `object` The object with keys to filter.
  208. * @param {String|Array} `patterns` One or more glob patterns to use for matching.
  209. * @param {Object} `options` See available [options](#options) for changing how matches are performed
  210. * @return {Object} Returns an object with only keys that match the given patterns.
  211. * @api public
  212. */
  213. micromatch.matchKeys = (obj, patterns, options) => {
  214. if (!utils.isObject(obj)) {
  215. throw new TypeError('Expected the first argument to be an object');
  216. }
  217. let keys = micromatch(Object.keys(obj), patterns, options);
  218. let res = {};
  219. for (let key of keys) res[key] = obj[key];
  220. return res;
  221. };
  222. /**
  223. * Returns true if some of the strings in the given `list` match any of the given glob `patterns`.
  224. *
  225. * ```js
  226. * const mm = require('micromatch');
  227. * // mm.some(list, patterns[, options]);
  228. *
  229. * console.log(mm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js']));
  230. * // true
  231. * console.log(mm.some(['foo.js'], ['*.js', '!foo.js']));
  232. * // false
  233. * ```
  234. * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found.
  235. * @param {String|Array} `patterns` One or more glob patterns to use for matching.
  236. * @param {Object} `options` See available [options](#options) for changing how matches are performed
  237. * @return {Boolean} Returns true if any patterns match `str`
  238. * @api public
  239. */
  240. micromatch.some = (list, patterns, options) => {
  241. let items = [].concat(list);
  242. for (let pattern of [].concat(patterns)) {
  243. let isMatch = picomatch(String(pattern), options);
  244. if (items.some(item => isMatch(item))) {
  245. return true;
  246. }
  247. }
  248. return false;
  249. };
  250. /**
  251. * Returns true if every string in the given `list` matches
  252. * any of the given glob `patterns`.
  253. *
  254. * ```js
  255. * const mm = require('micromatch');
  256. * // mm.every(list, patterns[, options]);
  257. *
  258. * console.log(mm.every('foo.js', ['foo.js']));
  259. * // true
  260. * console.log(mm.every(['foo.js', 'bar.js'], ['*.js']));
  261. * // true
  262. * console.log(mm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js']));
  263. * // false
  264. * console.log(mm.every(['foo.js'], ['*.js', '!foo.js']));
  265. * // false
  266. * ```
  267. * @param {String|Array} `list` The string or array of strings to test.
  268. * @param {String|Array} `patterns` One or more glob patterns to use for matching.
  269. * @param {Object} `options` See available [options](#options) for changing how matches are performed
  270. * @return {Boolean} Returns true if any patterns match `str`
  271. * @api public
  272. */
  273. micromatch.every = (list, patterns, options) => {
  274. let items = [].concat(list);
  275. for (let pattern of [].concat(patterns)) {
  276. let isMatch = picomatch(String(pattern), options);
  277. if (!items.every(item => isMatch(item))) {
  278. return false;
  279. }
  280. }
  281. return true;
  282. };
  283. /**
  284. * Returns true if **all** of the given `patterns` match
  285. * the specified string.
  286. *
  287. * ```js
  288. * const mm = require('micromatch');
  289. * // mm.all(string, patterns[, options]);
  290. *
  291. * console.log(mm.all('foo.js', ['foo.js']));
  292. * // true
  293. *
  294. * console.log(mm.all('foo.js', ['*.js', '!foo.js']));
  295. * // false
  296. *
  297. * console.log(mm.all('foo.js', ['*.js', 'foo.js']));
  298. * // true
  299. *
  300. * console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js']));
  301. * // true
  302. * ```
  303. * @param {String|Array} `str` The string to test.
  304. * @param {String|Array} `patterns` One or more glob patterns to use for matching.
  305. * @param {Object} `options` See available [options](#options) for changing how matches are performed
  306. * @return {Boolean} Returns true if any patterns match `str`
  307. * @api public
  308. */
  309. micromatch.all = (str, patterns, options) => {
  310. if (typeof str !== 'string') {
  311. throw new TypeError(`Expected a string: "${util.inspect(str)}"`);
  312. }
  313. return [].concat(patterns).every(p => picomatch(p, options)(str));
  314. };
  315. /**
  316. * Returns an array of matches captured by `pattern` in `string, or `null` if the pattern did not match.
  317. *
  318. * ```js
  319. * const mm = require('micromatch');
  320. * // mm.capture(pattern, string[, options]);
  321. *
  322. * console.log(mm.capture('test/*.js', 'test/foo.js'));
  323. * //=> ['foo']
  324. * console.log(mm.capture('test/*.js', 'foo/bar.css'));
  325. * //=> null
  326. * ```
  327. * @param {String} `glob` Glob pattern to use for matching.
  328. * @param {String} `input` String to match
  329. * @param {Object} `options` See available [options](#options) for changing how matches are performed
  330. * @return {Boolean} Returns an array of captures if the input matches the glob pattern, otherwise `null`.
  331. * @api public
  332. */
  333. micromatch.capture = (glob, input, options) => {
  334. let posix = utils.isWindows(options);
  335. let regex = picomatch.makeRe(String(glob), { ...options, capture: true });
  336. let match = regex.exec(posix ? utils.toPosixSlashes(input) : input);
  337. if (match) {
  338. return match.slice(1).map(v => v === void 0 ? '' : v);
  339. }
  340. };
  341. /**
  342. * Create a regular expression from the given glob `pattern`.
  343. *
  344. * ```js
  345. * const mm = require('micromatch');
  346. * // mm.makeRe(pattern[, options]);
  347. *
  348. * console.log(mm.makeRe('*.js'));
  349. * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/
  350. * ```
  351. * @param {String} `pattern` A glob pattern to convert to regex.
  352. * @param {Object} `options`
  353. * @return {RegExp} Returns a regex created from the given pattern.
  354. * @api public
  355. */
  356. micromatch.makeRe = (...args) => picomatch.makeRe(...args);
  357. /**
  358. * Scan a glob pattern to separate the pattern into segments. Used
  359. * by the [split](#split) method.
  360. *
  361. * ```js
  362. * const mm = require('micromatch');
  363. * const state = mm.scan(pattern[, options]);
  364. * ```
  365. * @param {String} `pattern`
  366. * @param {Object} `options`
  367. * @return {Object} Returns an object with
  368. * @api public
  369. */
  370. micromatch.scan = (...args) => picomatch.scan(...args);
  371. /**
  372. * Parse a glob pattern to create the source string for a regular
  373. * expression.
  374. *
  375. * ```js
  376. * const mm = require('micromatch');
  377. * const state = mm(pattern[, options]);
  378. * ```
  379. * @param {String} `glob`
  380. * @param {Object} `options`
  381. * @return {Object} Returns an object with useful properties and output to be used as regex source string.
  382. * @api public
  383. */
  384. micromatch.parse = (patterns, options) => {
  385. let res = [];
  386. for (let pattern of [].concat(patterns || [])) {
  387. for (let str of braces(String(pattern), options)) {
  388. res.push(picomatch.parse(str, options));
  389. }
  390. }
  391. return res;
  392. };
  393. /**
  394. * Process the given brace `pattern`.
  395. *
  396. * ```js
  397. * const { braces } = require('micromatch');
  398. * console.log(braces('foo/{a,b,c}/bar'));
  399. * //=> [ 'foo/(a|b|c)/bar' ]
  400. *
  401. * console.log(braces('foo/{a,b,c}/bar', { expand: true }));
  402. * //=> [ 'foo/a/bar', 'foo/b/bar', 'foo/c/bar' ]
  403. * ```
  404. * @param {String} `pattern` String with brace pattern to process.
  405. * @param {Object} `options` Any [options](#options) to change how expansion is performed. See the [braces][] library for all available options.
  406. * @return {Array}
  407. * @api public
  408. */
  409. micromatch.braces = (pattern, options) => {
  410. if (typeof pattern !== 'string') throw new TypeError('Expected a string');
  411. if ((options && options.nobrace === true) || !/\{.*\}/.test(pattern)) {
  412. return [pattern];
  413. }
  414. return braces(pattern, options);
  415. };
  416. /**
  417. * Expand braces
  418. */
  419. micromatch.braceExpand = (pattern, options) => {
  420. if (typeof pattern !== 'string') throw new TypeError('Expected a string');
  421. return micromatch.braces(pattern, { ...options, expand: true });
  422. };
  423. /**
  424. * Expose micromatch
  425. */
  426. var micromatch_1 = micromatch;
  427. function ensureArray(thing) {
  428. if (Array.isArray(thing))
  429. return thing;
  430. if (thing == undefined)
  431. return [];
  432. return [thing];
  433. }
  434. function getMatcherString(id, resolutionBase) {
  435. if (resolutionBase === false) {
  436. return id;
  437. }
  438. return path.resolve(...(typeof resolutionBase === 'string' ? [resolutionBase, id] : [id]));
  439. }
  440. const createFilter = function createFilter(include, exclude, options) {
  441. const resolutionBase = options && options.resolve;
  442. const getMatcher = (id) => {
  443. return id instanceof RegExp
  444. ? id
  445. : {
  446. test: micromatch_1.matcher(getMatcherString(id, resolutionBase)
  447. .split(path.sep)
  448. .join('/'), { dot: true })
  449. };
  450. };
  451. const includeMatchers = ensureArray(include).map(getMatcher);
  452. const excludeMatchers = ensureArray(exclude).map(getMatcher);
  453. return function (id) {
  454. if (typeof id !== 'string')
  455. return false;
  456. if (/\0/.test(id))
  457. return false;
  458. id = id.split(path.sep).join('/');
  459. for (let i = 0; i < excludeMatchers.length; ++i) {
  460. const matcher = excludeMatchers[i];
  461. if (matcher.test(id))
  462. return false;
  463. }
  464. for (let i = 0; i < includeMatchers.length; ++i) {
  465. const matcher = includeMatchers[i];
  466. if (matcher.test(id))
  467. return true;
  468. }
  469. return !includeMatchers.length;
  470. };
  471. };
  472. class FileWatcher {
  473. constructor(task, chokidarOptions) {
  474. this.transformWatchers = new Map();
  475. this.chokidarOptions = chokidarOptions;
  476. this.task = task;
  477. this.watcher = this.createWatcher(null);
  478. }
  479. close() {
  480. this.watcher.close();
  481. for (const watcher of this.transformWatchers.values()) {
  482. watcher.close();
  483. }
  484. }
  485. unwatch(id) {
  486. this.watcher.unwatch(id);
  487. const transformWatcher = this.transformWatchers.get(id);
  488. if (transformWatcher) {
  489. this.transformWatchers.delete(id);
  490. transformWatcher.close();
  491. }
  492. }
  493. watch(id, isTransformDependency) {
  494. if (isTransformDependency) {
  495. const watcher = this.transformWatchers.get(id) || this.createWatcher(id);
  496. watcher.add(id);
  497. this.transformWatchers.set(id, watcher);
  498. }
  499. else {
  500. this.watcher.add(id);
  501. }
  502. }
  503. createWatcher(transformWatcherId) {
  504. const task = this.task;
  505. const isLinux = require$$2.platform() === 'linux';
  506. const isTransformDependency = transformWatcherId !== null;
  507. const handleChange = (id, event) => {
  508. const changedId = transformWatcherId || id;
  509. if (isLinux) {
  510. // unwatching and watching fixes an issue with chokidar where on certain systems,
  511. // a file that was unlinked and immediately recreated would create a change event
  512. // but then no longer any further events
  513. watcher.unwatch(changedId);
  514. watcher.add(changedId);
  515. }
  516. task.invalidate(changedId, { isTransformDependency, event });
  517. };
  518. const watcher = index.chokidar
  519. .watch([], this.chokidarOptions)
  520. .on('add', id => handleChange(id, 'create'))
  521. .on('change', id => handleChange(id, 'update'))
  522. .on('unlink', id => handleChange(id, 'delete'));
  523. return watcher;
  524. }
  525. }
  526. const eventsRewrites = {
  527. create: {
  528. create: 'buggy',
  529. delete: null,
  530. update: 'create'
  531. },
  532. delete: {
  533. create: 'update',
  534. delete: 'buggy',
  535. update: 'buggy'
  536. },
  537. update: {
  538. create: 'buggy',
  539. delete: 'delete',
  540. update: 'update'
  541. }
  542. };
  543. class Watcher {
  544. constructor(configs, emitter) {
  545. this.buildDelay = 0;
  546. this.buildTimeout = null;
  547. this.invalidatedIds = new Map();
  548. this.rerun = false;
  549. this.emitter = emitter;
  550. emitter.close = this.close.bind(this);
  551. this.tasks = configs.map(config => new Task(this, config));
  552. this.buildDelay = configs.reduce((buildDelay, { watch }) => watch && typeof watch.buildDelay === 'number'
  553. ? Math.max(buildDelay, watch.buildDelay)
  554. : buildDelay, this.buildDelay);
  555. this.running = true;
  556. process.nextTick(() => this.run());
  557. }
  558. close() {
  559. if (this.buildTimeout)
  560. clearTimeout(this.buildTimeout);
  561. for (const task of this.tasks) {
  562. task.close();
  563. }
  564. this.emitter.emit('close');
  565. this.emitter.removeAllListeners();
  566. }
  567. invalidate(file) {
  568. if (file) {
  569. const prevEvent = this.invalidatedIds.get(file.id);
  570. const event = prevEvent ? eventsRewrites[prevEvent][file.event] : file.event;
  571. if (event === 'buggy') {
  572. //TODO: throws or warn? Currently just ignore, uses new event
  573. this.invalidatedIds.set(file.id, file.event);
  574. }
  575. else if (event === null) {
  576. this.invalidatedIds.delete(file.id);
  577. }
  578. else {
  579. this.invalidatedIds.set(file.id, event);
  580. }
  581. }
  582. if (this.running) {
  583. this.rerun = true;
  584. return;
  585. }
  586. if (this.buildTimeout)
  587. clearTimeout(this.buildTimeout);
  588. this.buildTimeout = setTimeout(() => {
  589. this.buildTimeout = null;
  590. for (const [id, event] of this.invalidatedIds.entries()) {
  591. this.emitter.emit('change', id, { event });
  592. }
  593. this.invalidatedIds.clear();
  594. this.emitter.emit('restart');
  595. this.run();
  596. }, this.buildDelay);
  597. }
  598. async run() {
  599. this.running = true;
  600. this.emitter.emit('event', {
  601. code: 'START'
  602. });
  603. for (const task of this.tasks) {
  604. await task.run();
  605. }
  606. this.running = false;
  607. this.emitter.emit('event', {
  608. code: 'END'
  609. });
  610. if (this.rerun) {
  611. this.rerun = false;
  612. this.invalidate();
  613. }
  614. }
  615. }
  616. class Task {
  617. constructor(watcher, config) {
  618. this.cache = { modules: [] };
  619. this.watchFiles = [];
  620. this.invalidated = true;
  621. this.watcher = watcher;
  622. this.closed = false;
  623. this.watched = new Set();
  624. this.skipWrite = Boolean(config.watch && config.watch.skipWrite);
  625. this.options = mergeOptions.mergeOptions(config);
  626. this.outputs = this.options.output;
  627. this.outputFiles = this.outputs.map(output => {
  628. if (output.file || output.dir)
  629. return path.resolve(output.file || output.dir);
  630. return undefined;
  631. });
  632. const watchOptions = this.options.watch || {};
  633. this.filter = createFilter(watchOptions.include, watchOptions.exclude);
  634. this.fileWatcher = new FileWatcher(this, {
  635. ...watchOptions.chokidar,
  636. disableGlobbing: true,
  637. ignoreInitial: true
  638. });
  639. }
  640. close() {
  641. this.closed = true;
  642. this.fileWatcher.close();
  643. }
  644. invalidate(id, details) {
  645. this.invalidated = true;
  646. if (details.isTransformDependency) {
  647. for (const module of this.cache.modules) {
  648. if (module.transformDependencies.indexOf(id) === -1)
  649. continue;
  650. // effective invalidation
  651. module.originalCode = null;
  652. }
  653. }
  654. this.watcher.invalidate({ id, event: details.event });
  655. }
  656. async run() {
  657. if (!this.invalidated)
  658. return;
  659. this.invalidated = false;
  660. const options = {
  661. ...this.options,
  662. cache: this.cache
  663. };
  664. const start = Date.now();
  665. this.watcher.emitter.emit('event', {
  666. code: 'BUNDLE_START',
  667. input: this.options.input,
  668. output: this.outputFiles
  669. });
  670. let result = null;
  671. try {
  672. result = await rollup.rollupInternal(options, this.watcher.emitter);
  673. if (this.closed) {
  674. return;
  675. }
  676. this.updateWatchedFiles(result);
  677. this.skipWrite || (await Promise.all(this.outputs.map(output => result.write(output))));
  678. this.watcher.emitter.emit('event', {
  679. code: 'BUNDLE_END',
  680. duration: Date.now() - start,
  681. input: this.options.input,
  682. output: this.outputFiles,
  683. result
  684. });
  685. }
  686. catch (error) {
  687. if (!this.closed) {
  688. if (Array.isArray(error.watchFiles)) {
  689. for (const id of error.watchFiles) {
  690. this.watchFile(id);
  691. }
  692. }
  693. if (error.id) {
  694. this.cache.modules = this.cache.modules.filter(module => module.id !== error.id);
  695. }
  696. }
  697. this.watcher.emitter.emit('event', {
  698. code: 'ERROR',
  699. error,
  700. result
  701. });
  702. }
  703. }
  704. updateWatchedFiles(result) {
  705. const previouslyWatched = this.watched;
  706. this.watched = new Set();
  707. this.watchFiles = result.watchFiles;
  708. this.cache = result.cache;
  709. for (const id of this.watchFiles) {
  710. this.watchFile(id);
  711. }
  712. for (const module of this.cache.modules) {
  713. for (const depId of module.transformDependencies) {
  714. this.watchFile(depId, true);
  715. }
  716. }
  717. for (const id of previouslyWatched) {
  718. if (!this.watched.has(id)) {
  719. this.fileWatcher.unwatch(id);
  720. }
  721. }
  722. }
  723. watchFile(id, isTransformDependency = false) {
  724. if (!this.filter(id))
  725. return;
  726. this.watched.add(id);
  727. if (this.outputFiles.some(file => file === id)) {
  728. throw new Error('Cannot import the generated bundle');
  729. }
  730. // this is necessary to ensure that any 'renamed' files
  731. // continue to be watched following an error
  732. this.fileWatcher.watch(id, isTransformDependency);
  733. }
  734. }
  735. exports.Task = Task;
  736. exports.Watcher = Watcher;
  737. //# sourceMappingURL=watch.js.map