watch.js 24 KB

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