| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 | 'use strict';function path() {  const data = _interopRequireWildcard(require('path'));  path = function () {    return data;  };  return data;}function _fbWatchman() {  const data = _interopRequireDefault(require('fb-watchman'));  _fbWatchman = function () {    return data;  };  return data;}var _constants = _interopRequireDefault(require('../constants'));var fastPath = _interopRequireWildcard(require('../lib/fast_path'));var _normalizePathSep = _interopRequireDefault(  require('../lib/normalizePathSep'));function _interopRequireDefault(obj) {  return obj && obj.__esModule ? obj : {default: obj};}function _getRequireWildcardCache(nodeInterop) {  if (typeof WeakMap !== 'function') return null;  var cacheBabelInterop = new WeakMap();  var cacheNodeInterop = new WeakMap();  return (_getRequireWildcardCache = function (nodeInterop) {    return nodeInterop ? cacheNodeInterop : cacheBabelInterop;  })(nodeInterop);}function _interopRequireWildcard(obj, nodeInterop) {  if (!nodeInterop && obj && obj.__esModule) {    return obj;  }  if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {    return {default: obj};  }  var cache = _getRequireWildcardCache(nodeInterop);  if (cache && cache.has(obj)) {    return cache.get(obj);  }  var newObj = {};  var hasPropertyDescriptor =    Object.defineProperty && Object.getOwnPropertyDescriptor;  for (var key in obj) {    if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {      var desc = hasPropertyDescriptor        ? Object.getOwnPropertyDescriptor(obj, key)        : null;      if (desc && (desc.get || desc.set)) {        Object.defineProperty(newObj, key, desc);      } else {        newObj[key] = obj[key];      }    }  }  newObj.default = obj;  if (cache) {    cache.set(obj, newObj);  }  return newObj;}/** * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */const watchmanURL = 'https://facebook.github.io/watchman/docs/troubleshooting';function WatchmanError(error) {  error.message =    `Watchman error: ${error.message.trim()}. Make sure watchman ` +    `is running for this project. See ${watchmanURL}.`;  return error;}/** * Wrap watchman capabilityCheck method as a promise. * * @param client watchman client * @param caps capabilities to verify * @returns a promise resolving to a list of verified capabilities */async function capabilityCheck(client, caps) {  return new Promise((resolve, reject) => {    client.capabilityCheck(      // @ts-expect-error: incorrectly typed      caps,      (error, response) => {        if (error) {          reject(error);        } else {          resolve(response);        }      }    );  });}module.exports = async function watchmanCrawl(options) {  const fields = ['name', 'exists', 'mtime_ms', 'size'];  const {data, extensions, ignore, rootDir, roots} = options;  const defaultWatchExpression = ['allof', ['type', 'f']];  const clocks = data.clocks;  const client = new (_fbWatchman().default.Client)(); // https://facebook.github.io/watchman/docs/capabilities.html  // Check adds about ~28ms  const capabilities = await capabilityCheck(client, {    // If a required capability is missing then an error will be thrown,    // we don't need this assertion, so using optional instead.    optional: ['suffix-set']  });  if (    capabilities !== null &&    capabilities !== void 0 &&    capabilities.capabilities['suffix-set']  ) {    // If available, use the optimized `suffix-set` operation:    // https://facebook.github.io/watchman/docs/expr/suffix.html#suffix-set    defaultWatchExpression.push(['suffix', extensions]);  } else {    // Otherwise use the older and less optimal suffix tuple array    defaultWatchExpression.push([      'anyof',      ...extensions.map(extension => ['suffix', extension])    ]);  }  let clientError;  client.on('error', error => (clientError = WatchmanError(error)));  const cmd = (...args) =>    new Promise((resolve, reject) =>      client.command(args, (error, result) =>        error ? reject(WatchmanError(error)) : resolve(result)      )    );  if (options.computeSha1) {    const {capabilities} = await cmd('list-capabilities');    if (capabilities.indexOf('field-content.sha1hex') !== -1) {      fields.push('content.sha1hex');    }  }  async function getWatchmanRoots(roots) {    const watchmanRoots = new Map();    await Promise.all(      roots.map(async root => {        const response = await 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 watchmanRoots;  }  async function queryWatchmanForDirs(rootProjectDirMappings) {    const results = new Map();    let isFresh = false;    await Promise.all(      Array.from(rootProjectDirMappings).map(        async ([root, directoryFilters]) => {          var _since$scm;          const expression = Array.from(defaultWatchExpression);          const glob = [];          if (directoryFilters.length > 0) {            expression.push([              'anyof',              ...directoryFilters.map(dir => ['dirname', dir])            ]);            for (const directory of directoryFilters) {              for (const extension of extensions) {                glob.push(`${directory}/**/*.${extension}`);              }            }          } else {            for (const extension of extensions) {              glob.push(`**/*.${extension}`);            }          } // Jest is only going to store one type of clock; a string that          // represents a local clock. However, the Watchman crawler supports          // a second type of clock that can be written by automation outside of          // Jest, called an "scm query", which fetches changed files based on          // source control mergebases. The reason this is necessary is because          // local clocks are not portable across systems, but scm queries are.          // By using scm queries, we can create the haste map on a different          // system and import it, transforming the clock into a local clock.          const since = clocks.get(fastPath.relative(rootDir, root));          const query =            since !== undefined // Use the `since` generator if we have a clock available              ? {                  expression,                  fields,                  since                } // Otherwise use the `glob` filter              : {                  expression,                  fields,                  glob,                  glob_includedotfiles: true                };          const response = await cmd('query', root, query);          if ('warning' in response) {            console.warn('watchman warning: ', response.warning);          } // When a source-control query is used, we ignore the "is fresh"          // response from Watchman because it will be true despite the query          // being incremental.          const isSourceControlQuery =            typeof since !== 'string' &&            (since === null || since === void 0              ? void 0              : (_since$scm = since.scm) === null || _since$scm === void 0              ? void 0              : _since$scm['mergebase-with']) !== undefined;          if (!isSourceControlQuery) {            isFresh = isFresh || response.is_fresh_instance;          }          results.set(root, response);        }      )    );    return {      isFresh,      results    };  }  let files = data.files;  let removedFiles = new Map();  const changedFiles = new Map();  let results;  let isFresh = false;  try {    const watchmanRoots = await getWatchmanRoots(roots);    const watchmanFileResults = await 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;    }    results = watchmanFileResults.results;  } finally {    client.end();  }  if (clientError) {    throw clientError;  }  for (const [watchRoot, response] of results) {    const fsRoot = (0, _normalizePathSep.default)(watchRoot);    const relativeFsRoot = fastPath.relative(rootDir, fsRoot);    clocks.set(      relativeFsRoot, // Ensure we persist only the local clock.      typeof response.clock === 'string' ? response.clock : response.clock.clock    );    for (const fileData of response.files) {      const filePath =        fsRoot + path().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 = undefined;        }        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 {          var _sha1hex;          // See ../constants.ts          nextData = [            '',            mtime,            size,            0,            '',            (_sha1hex = sha1hex) !== null && _sha1hex !== void 0              ? _sha1hex              : null          ];        }        files.set(relativeFilePath, nextData);        changedFiles.set(relativeFilePath, nextData);      }    }  }  data.files = files;  return {    changedFiles: isFresh ? undefined : changedFiles,    hasteMap: data,    removedFiles  };};
 |