589 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			589 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| function _path() {
 | |
|   const data = _interopRequireDefault(require('path'));
 | |
| 
 | |
|   _path = function _path() {
 | |
|     return data;
 | |
|   };
 | |
| 
 | |
|   return data;
 | |
| }
 | |
| 
 | |
| function _fbWatchman() {
 | |
|   const data = _interopRequireDefault(require('fb-watchman'));
 | |
| 
 | |
|   _fbWatchman = function _fbWatchman() {
 | |
|     return data;
 | |
|   };
 | |
| 
 | |
|   return data;
 | |
| }
 | |
| 
 | |
| var fastPath = _interopRequireWildcard(require('../lib/fast_path'));
 | |
| 
 | |
| var _normalizePathSep = _interopRequireDefault(
 | |
|   require('../lib/normalizePathSep')
 | |
| );
 | |
| 
 | |
| var _constants = _interopRequireDefault(require('../constants'));
 | |
| 
 | |
| function _interopRequireWildcard(obj) {
 | |
|   if (obj && obj.__esModule) {
 | |
|     return obj;
 | |
|   } else {
 | |
|     var newObj = {};
 | |
|     if (obj != null) {
 | |
|       for (var key in obj) {
 | |
|         if (Object.prototype.hasOwnProperty.call(obj, key)) {
 | |
|           var desc =
 | |
|             Object.defineProperty && Object.getOwnPropertyDescriptor
 | |
|               ? Object.getOwnPropertyDescriptor(obj, key)
 | |
|               : {};
 | |
|           if (desc.get || desc.set) {
 | |
|             Object.defineProperty(newObj, key, desc);
 | |
|           } else {
 | |
|             newObj[key] = obj[key];
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     newObj.default = obj;
 | |
|     return newObj;
 | |
|   }
 | |
| }
 | |
| 
 | |
| function _interopRequireDefault(obj) {
 | |
|   return obj && obj.__esModule ? obj : {default: obj};
 | |
| }
 | |
| 
 | |
| function _slicedToArray(arr, i) {
 | |
|   return (
 | |
|     _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest()
 | |
|   );
 | |
| }
 | |
| 
 | |
| function _nonIterableRest() {
 | |
|   throw new TypeError('Invalid attempt to destructure non-iterable instance');
 | |
| }
 | |
| 
 | |
| function _iterableToArrayLimit(arr, i) {
 | |
|   var _arr = [];
 | |
|   var _n = true;
 | |
|   var _d = false;
 | |
|   var _e = undefined;
 | |
|   try {
 | |
|     for (
 | |
|       var _i = arr[Symbol.iterator](), _s;
 | |
|       !(_n = (_s = _i.next()).done);
 | |
|       _n = true
 | |
|     ) {
 | |
|       _arr.push(_s.value);
 | |
|       if (i && _arr.length === i) break;
 | |
|     }
 | |
|   } catch (err) {
 | |
|     _d = true;
 | |
|     _e = err;
 | |
|   } finally {
 | |
|     try {
 | |
|       if (!_n && _i['return'] != null) _i['return']();
 | |
|     } finally {
 | |
|       if (_d) throw _e;
 | |
|     }
 | |
|   }
 | |
|   return _arr;
 | |
| }
 | |
| 
 | |
| function _arrayWithHoles(arr) {
 | |
|   if (Array.isArray(arr)) return arr;
 | |
| }
 | |
| 
 | |
| function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
 | |
|   try {
 | |
|     var info = gen[key](arg);
 | |
|     var value = info.value;
 | |
|   } catch (error) {
 | |
|     reject(error);
 | |
|     return;
 | |
|   }
 | |
|   if (info.done) {
 | |
|     resolve(value);
 | |
|   } else {
 | |
|     Promise.resolve(value).then(_next, _throw);
 | |
|   }
 | |
| }
 | |
| 
 | |
| function _asyncToGenerator(fn) {
 | |
|   return function() {
 | |
|     var self = this,
 | |
|       args = arguments;
 | |
|     return new Promise(function(resolve, reject) {
 | |
|       var gen = fn.apply(self, args);
 | |
|       function _next(value) {
 | |
|         asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
 | |
|       }
 | |
|       function _throw(err) {
 | |
|         asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
 | |
|       }
 | |
|       _next(undefined);
 | |
|     });
 | |
|   };
 | |
| }
 | |
| 
 | |
| const watchmanURL =
 | |
|   'https://facebook.github.io/watchman/docs/troubleshooting.html';
 | |
| 
 | |
| function WatchmanError(error) {
 | |
|   error.message =
 | |
|     `Watchman error: ${error.message.trim()}. Make sure watchman ` +
 | |
|     `is running for this project. See ${watchmanURL}.`;
 | |
|   return error;
 | |
| }
 | |
| 
 | |
| module.exports =
 | |
|   /*#__PURE__*/
 | |
|   (function() {
 | |
|     var _watchmanCrawl = _asyncToGenerator(function*(options) {
 | |
|       const fields = ['name', 'exists', 'mtime_ms', 'size'];
 | |
|       const data = options.data,
 | |
|         extensions = options.extensions,
 | |
|         ignore = options.ignore,
 | |
|         rootDir = options.rootDir,
 | |
|         roots = options.roots;
 | |
|       const defaultWatchExpression = [
 | |
|         'allof',
 | |
|         ['type', 'f'],
 | |
|         ['anyof', ...extensions.map(extension => ['suffix', extension])]
 | |
|       ];
 | |
|       const clocks = data.clocks;
 | |
|       const client = new (_fbWatchman()).default.Client();
 | |
|       let clientError;
 | |
|       client.on('error', error => (clientError = WatchmanError(error))); // TODO: type better than `any`
 | |
| 
 | |
|       const cmd = (...args) =>
 | |
|         new Promise((resolve, reject) =>
 | |
|           client.command(args, (error, result) =>
 | |
|             error ? reject(WatchmanError(error)) : resolve(result)
 | |
|           )
 | |
|         );
 | |
| 
 | |
|       if (options.computeSha1) {
 | |
|         const _ref = yield cmd('list-capabilities'),
 | |
|           capabilities = _ref.capabilities;
 | |
| 
 | |
|         if (capabilities.indexOf('field-content.sha1hex') !== -1) {
 | |
|           fields.push('content.sha1hex');
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       function getWatchmanRoots(_x2) {
 | |
|         return _getWatchmanRoots.apply(this, arguments);
 | |
|       }
 | |
| 
 | |
|       function _getWatchmanRoots() {
 | |
|         _getWatchmanRoots = _asyncToGenerator(function*(roots) {
 | |
|           const watchmanRoots = new Map();
 | |
|           yield Promise.all(
 | |
|             roots.map(
 | |
|               /*#__PURE__*/
 | |
|               (function() {
 | |
|                 var _ref2 = _asyncToGenerator(function*(root) {
 | |
|                   const response = yield cmd('watch-project', root);
 | |
|                   const existing = watchmanRoots.get(response.watch); // A root can only be filtered if it was never seen with a
 | |
|                   // relative_path before.
 | |
| 
 | |
|                   const canBeFiltered = !existing || existing.length > 0;
 | |
| 
 | |
|                   if (canBeFiltered) {
 | |
|                     if (response.relative_path) {
 | |
|                       watchmanRoots.set(
 | |
|                         response.watch,
 | |
|                         (existing || []).concat(response.relative_path)
 | |
|                       );
 | |
|                     } else {
 | |
|                       // Make the filter directories an empty array to signal that this
 | |
|                       // root was already seen and needs to be watched for all files or
 | |
|                       // directories.
 | |
|                       watchmanRoots.set(response.watch, []);
 | |
|                     }
 | |
|                   }
 | |
|                 });
 | |
| 
 | |
|                 return function(_x4) {
 | |
|                   return _ref2.apply(this, arguments);
 | |
|                 };
 | |
|               })()
 | |
|             )
 | |
|           );
 | |
|           return watchmanRoots;
 | |
|         });
 | |
|         return _getWatchmanRoots.apply(this, arguments);
 | |
|       }
 | |
| 
 | |
|       function queryWatchmanForDirs(_x3) {
 | |
|         return _queryWatchmanForDirs.apply(this, arguments);
 | |
|       }
 | |
| 
 | |
|       function _queryWatchmanForDirs() {
 | |
|         _queryWatchmanForDirs = _asyncToGenerator(function*(
 | |
|           rootProjectDirMappings
 | |
|         ) {
 | |
|           const files = new Map();
 | |
|           let isFresh = false;
 | |
|           yield Promise.all(
 | |
|             Array.from(rootProjectDirMappings).map(
 | |
|               /*#__PURE__*/
 | |
|               (function() {
 | |
|                 var _ref3 = _asyncToGenerator(function*([
 | |
|                   root,
 | |
|                   directoryFilters
 | |
|                 ]) {
 | |
|                   const expression = Array.from(defaultWatchExpression);
 | |
|                   const glob = [];
 | |
| 
 | |
|                   if (directoryFilters.length > 0) {
 | |
|                     expression.push([
 | |
|                       'anyof',
 | |
|                       ...directoryFilters.map(dir => ['dirname', dir])
 | |
|                     ]);
 | |
|                     var _iteratorNormalCompletion2 = true;
 | |
|                     var _didIteratorError2 = false;
 | |
|                     var _iteratorError2 = undefined;
 | |
| 
 | |
|                     try {
 | |
|                       for (
 | |
|                         var _iterator2 = directoryFilters[Symbol.iterator](),
 | |
|                           _step2;
 | |
|                         !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next())
 | |
|                           .done);
 | |
|                         _iteratorNormalCompletion2 = true
 | |
|                       ) {
 | |
|                         const directory = _step2.value;
 | |
|                         var _iteratorNormalCompletion3 = true;
 | |
|                         var _didIteratorError3 = false;
 | |
|                         var _iteratorError3 = undefined;
 | |
| 
 | |
|                         try {
 | |
|                           for (
 | |
|                             var _iterator3 = extensions[Symbol.iterator](),
 | |
|                               _step3;
 | |
|                             !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next())
 | |
|                               .done);
 | |
|                             _iteratorNormalCompletion3 = true
 | |
|                           ) {
 | |
|                             const extension = _step3.value;
 | |
|                             glob.push(`${directory}/**/*.${extension}`);
 | |
|                           }
 | |
|                         } catch (err) {
 | |
|                           _didIteratorError3 = true;
 | |
|                           _iteratorError3 = err;
 | |
|                         } finally {
 | |
|                           try {
 | |
|                             if (
 | |
|                               !_iteratorNormalCompletion3 &&
 | |
|                               _iterator3.return != null
 | |
|                             ) {
 | |
|                               _iterator3.return();
 | |
|                             }
 | |
|                           } finally {
 | |
|                             if (_didIteratorError3) {
 | |
|                               throw _iteratorError3;
 | |
|                             }
 | |
|                           }
 | |
|                         }
 | |
|                       }
 | |
|                     } catch (err) {
 | |
|                       _didIteratorError2 = true;
 | |
|                       _iteratorError2 = err;
 | |
|                     } finally {
 | |
|                       try {
 | |
|                         if (
 | |
|                           !_iteratorNormalCompletion2 &&
 | |
|                           _iterator2.return != null
 | |
|                         ) {
 | |
|                           _iterator2.return();
 | |
|                         }
 | |
|                       } finally {
 | |
|                         if (_didIteratorError2) {
 | |
|                           throw _iteratorError2;
 | |
|                         }
 | |
|                       }
 | |
|                     }
 | |
|                   } else {
 | |
|                     var _iteratorNormalCompletion4 = true;
 | |
|                     var _didIteratorError4 = false;
 | |
|                     var _iteratorError4 = undefined;
 | |
| 
 | |
|                     try {
 | |
|                       for (
 | |
|                         var _iterator4 = extensions[Symbol.iterator](), _step4;
 | |
|                         !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next())
 | |
|                           .done);
 | |
|                         _iteratorNormalCompletion4 = true
 | |
|                       ) {
 | |
|                         const extension = _step4.value;
 | |
|                         glob.push(`**/*.${extension}`);
 | |
|                       }
 | |
|                     } catch (err) {
 | |
|                       _didIteratorError4 = true;
 | |
|                       _iteratorError4 = err;
 | |
|                     } finally {
 | |
|                       try {
 | |
|                         if (
 | |
|                           !_iteratorNormalCompletion4 &&
 | |
|                           _iterator4.return != null
 | |
|                         ) {
 | |
|                           _iterator4.return();
 | |
|                         }
 | |
|                       } finally {
 | |
|                         if (_didIteratorError4) {
 | |
|                           throw _iteratorError4;
 | |
|                         }
 | |
|                       }
 | |
|                     }
 | |
|                   }
 | |
| 
 | |
|                   const relativeRoot = fastPath.relative(rootDir, root);
 | |
|                   const query = clocks.has(relativeRoot) // Use the `since` generator if we have a clock available
 | |
|                     ? {
 | |
|                         expression,
 | |
|                         fields,
 | |
|                         since: clocks.get(relativeRoot)
 | |
|                       } // Otherwise use the `glob` filter
 | |
|                     : {
 | |
|                         expression,
 | |
|                         fields,
 | |
|                         glob
 | |
|                       };
 | |
|                   const response = yield cmd('query', root, query);
 | |
| 
 | |
|                   if ('warning' in response) {
 | |
|                     console.warn('watchman warning: ', response.warning);
 | |
|                   }
 | |
| 
 | |
|                   isFresh = isFresh || response.is_fresh_instance;
 | |
|                   files.set(root, response);
 | |
|                 });
 | |
| 
 | |
|                 return function(_x5) {
 | |
|                   return _ref3.apply(this, arguments);
 | |
|                 };
 | |
|               })()
 | |
|             )
 | |
|           );
 | |
|           return {
 | |
|             files,
 | |
|             isFresh
 | |
|           };
 | |
|         });
 | |
|         return _queryWatchmanForDirs.apply(this, arguments);
 | |
|       }
 | |
| 
 | |
|       let files = data.files;
 | |
|       let removedFiles = new Map();
 | |
|       const changedFiles = new Map();
 | |
|       let watchmanFiles;
 | |
|       let isFresh = false;
 | |
| 
 | |
|       try {
 | |
|         const watchmanRoots = yield getWatchmanRoots(roots);
 | |
|         const watchmanFileResults = yield queryWatchmanForDirs(watchmanRoots); // Reset the file map if watchman was restarted and sends us a list of
 | |
|         // files.
 | |
| 
 | |
|         if (watchmanFileResults.isFresh) {
 | |
|           files = new Map();
 | |
|           removedFiles = new Map(data.files);
 | |
|           isFresh = true;
 | |
|         }
 | |
| 
 | |
|         watchmanFiles = watchmanFileResults.files;
 | |
|       } finally {
 | |
|         client.end();
 | |
|       }
 | |
| 
 | |
|       if (clientError) {
 | |
|         throw clientError;
 | |
|       } // TODO: remove non-null
 | |
| 
 | |
|       var _iteratorNormalCompletion = true;
 | |
|       var _didIteratorError = false;
 | |
|       var _iteratorError = undefined;
 | |
| 
 | |
|       try {
 | |
|         for (
 | |
|           var _iterator = watchmanFiles[Symbol.iterator](), _step;
 | |
|           !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
 | |
|           _iteratorNormalCompletion = true
 | |
|         ) {
 | |
|           const _step$value = _slicedToArray(_step.value, 2),
 | |
|             watchRoot = _step$value[0],
 | |
|             response = _step$value[1];
 | |
| 
 | |
|           const fsRoot = (0, _normalizePathSep.default)(watchRoot);
 | |
|           const relativeFsRoot = fastPath.relative(rootDir, fsRoot);
 | |
|           clocks.set(relativeFsRoot, response.clock);
 | |
|           var _iteratorNormalCompletion5 = true;
 | |
|           var _didIteratorError5 = false;
 | |
|           var _iteratorError5 = undefined;
 | |
| 
 | |
|           try {
 | |
|             for (
 | |
|               var _iterator5 = response.files[Symbol.iterator](), _step5;
 | |
|               !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done);
 | |
|               _iteratorNormalCompletion5 = true
 | |
|             ) {
 | |
|               const fileData = _step5.value;
 | |
|               const filePath =
 | |
|                 fsRoot +
 | |
|                 _path().default.sep +
 | |
|                 (0, _normalizePathSep.default)(fileData.name);
 | |
|               const relativeFilePath = fastPath.relative(rootDir, filePath);
 | |
|               const existingFileData = data.files.get(relativeFilePath); // If watchman is fresh, the removed files map starts with all files
 | |
|               // and we remove them as we verify they still exist.
 | |
| 
 | |
|               if (isFresh && existingFileData && fileData.exists) {
 | |
|                 removedFiles.delete(relativeFilePath);
 | |
|               }
 | |
| 
 | |
|               if (!fileData.exists) {
 | |
|                 // No need to act on files that do not exist and were not tracked.
 | |
|                 if (existingFileData) {
 | |
|                   files.delete(relativeFilePath); // If watchman is not fresh, we will know what specific files were
 | |
|                   // deleted since we last ran and can track only those files.
 | |
| 
 | |
|                   if (!isFresh) {
 | |
|                     removedFiles.set(relativeFilePath, existingFileData);
 | |
|                   }
 | |
|                 }
 | |
|               } else if (!ignore(filePath)) {
 | |
|                 const mtime =
 | |
|                   typeof fileData.mtime_ms === 'number'
 | |
|                     ? fileData.mtime_ms
 | |
|                     : fileData.mtime_ms.toNumber();
 | |
|                 const size = fileData.size;
 | |
|                 let sha1hex = fileData['content.sha1hex'];
 | |
| 
 | |
|                 if (typeof sha1hex !== 'string' || sha1hex.length !== 40) {
 | |
|                   sha1hex = null;
 | |
|                 }
 | |
| 
 | |
|                 let nextData;
 | |
| 
 | |
|                 if (
 | |
|                   existingFileData &&
 | |
|                   existingFileData[_constants.default.MTIME] === mtime
 | |
|                 ) {
 | |
|                   nextData = existingFileData;
 | |
|                 } else if (
 | |
|                   existingFileData &&
 | |
|                   sha1hex &&
 | |
|                   existingFileData[_constants.default.SHA1] === sha1hex
 | |
|                 ) {
 | |
|                   nextData = [
 | |
|                     existingFileData[0],
 | |
|                     mtime,
 | |
|                     existingFileData[2],
 | |
|                     existingFileData[3],
 | |
|                     existingFileData[4],
 | |
|                     existingFileData[5]
 | |
|                   ];
 | |
|                 } else {
 | |
|                   // See ../constants.ts
 | |
|                   nextData = ['', mtime, size, 0, '', sha1hex];
 | |
|                 }
 | |
| 
 | |
|                 const mappings = options.mapper
 | |
|                   ? options.mapper(filePath)
 | |
|                   : null;
 | |
| 
 | |
|                 if (mappings) {
 | |
|                   var _iteratorNormalCompletion6 = true;
 | |
|                   var _didIteratorError6 = false;
 | |
|                   var _iteratorError6 = undefined;
 | |
| 
 | |
|                   try {
 | |
|                     for (
 | |
|                       var _iterator6 = mappings[Symbol.iterator](), _step6;
 | |
|                       !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next())
 | |
|                         .done);
 | |
|                       _iteratorNormalCompletion6 = true
 | |
|                     ) {
 | |
|                       const absoluteVirtualFilePath = _step6.value;
 | |
| 
 | |
|                       if (!ignore(absoluteVirtualFilePath)) {
 | |
|                         const relativeVirtualFilePath = fastPath.relative(
 | |
|                           rootDir,
 | |
|                           absoluteVirtualFilePath
 | |
|                         );
 | |
|                         files.set(relativeVirtualFilePath, nextData);
 | |
|                         changedFiles.set(relativeVirtualFilePath, nextData);
 | |
|                       }
 | |
|                     }
 | |
|                   } catch (err) {
 | |
|                     _didIteratorError6 = true;
 | |
|                     _iteratorError6 = err;
 | |
|                   } finally {
 | |
|                     try {
 | |
|                       if (
 | |
|                         !_iteratorNormalCompletion6 &&
 | |
|                         _iterator6.return != null
 | |
|                       ) {
 | |
|                         _iterator6.return();
 | |
|                       }
 | |
|                     } finally {
 | |
|                       if (_didIteratorError6) {
 | |
|                         throw _iteratorError6;
 | |
|                       }
 | |
|                     }
 | |
|                   }
 | |
|                 } else {
 | |
|                   files.set(relativeFilePath, nextData);
 | |
|                   changedFiles.set(relativeFilePath, nextData);
 | |
|                 }
 | |
|               }
 | |
|             }
 | |
|           } catch (err) {
 | |
|             _didIteratorError5 = true;
 | |
|             _iteratorError5 = err;
 | |
|           } finally {
 | |
|             try {
 | |
|               if (!_iteratorNormalCompletion5 && _iterator5.return != null) {
 | |
|                 _iterator5.return();
 | |
|               }
 | |
|             } finally {
 | |
|               if (_didIteratorError5) {
 | |
|                 throw _iteratorError5;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       } catch (err) {
 | |
|         _didIteratorError = true;
 | |
|         _iteratorError = err;
 | |
|       } finally {
 | |
|         try {
 | |
|           if (!_iteratorNormalCompletion && _iterator.return != null) {
 | |
|             _iterator.return();
 | |
|           }
 | |
|         } finally {
 | |
|           if (_didIteratorError) {
 | |
|             throw _iteratorError;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       data.files = files;
 | |
|       return {
 | |
|         changedFiles: isFresh ? undefined : changedFiles,
 | |
|         hasteMap: data,
 | |
|         removedFiles
 | |
|       };
 | |
|     });
 | |
| 
 | |
|     function watchmanCrawl(_x) {
 | |
|       return _watchmanCrawl.apply(this, arguments);
 | |
|     }
 | |
| 
 | |
|     return watchmanCrawl;
 | |
|   })();
 |