metro-file-map
Advanced tools
Comparing version 0.72.3 to 0.73.0
{ | ||
"name": "metro-file-map", | ||
"version": "0.72.3", | ||
"version": "0.73.0", | ||
"description": "[Experimental] - 🚇 File crawling, watching and mapping for Metro", | ||
@@ -33,4 +33,4 @@ "main": "src/index.js", | ||
"optionalDependencies": { | ||
"fsevents": "^2.1.2" | ||
"fsevents": "^2.3.2" | ||
} | ||
} |
@@ -32,2 +32,3 @@ "use strict"; | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
@@ -70,5 +71,10 @@ const DEFAULT_PREFIX = "metro-file-map"; | ||
); | ||
} catch {} | ||
} catch (e) { | ||
if ((e === null || e === void 0 ? void 0 : e.code) === "ENOENT") { | ||
// Cache file not found - not considered an error. | ||
return null; | ||
} // Rethrow anything else. | ||
return null; | ||
throw e; | ||
} | ||
} | ||
@@ -75,0 +81,0 @@ |
@@ -67,2 +67,3 @@ "use strict"; | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
@@ -69,0 +70,0 @@ async function hasNativeFindSupport(forceNodeFilesystemAPI) { |
@@ -9,3 +9,4 @@ /** | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
"use strict"; |
218
src/index.js
@@ -31,2 +31,6 @@ "use strict"; | ||
var _checkWatchmanCapabilities = _interopRequireDefault( | ||
require("./lib/checkWatchmanCapabilities") | ||
); | ||
var _deepCloneInternalData = _interopRequireDefault( | ||
@@ -64,4 +68,2 @@ require("./lib/deepCloneInternalData") | ||
var _child_process = require("child_process"); | ||
var _events = _interopRequireDefault(require("events")); | ||
@@ -133,5 +135,5 @@ | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
// $FlowFixMe[untyped-import] - it's a fork: https://github.com/facebook/jest/pull/10919 | ||
// $FlowFixMe[untyped-import] - WatchmanWatcher | ||
// $FlowFixMe[untyped-import] - jest-regex-util | ||
@@ -144,2 +146,4 @@ // $FlowFixMe[untyped-import] - jest-worker | ||
const debug = require("debug")("Metro:FileMap"); | ||
const DuplicateHasteCandidatesError = | ||
@@ -161,13 +165,8 @@ _ModuleMap.default.DuplicateHasteCandidatesError; | ||
.join("|"); | ||
const canUseWatchman = (() => { | ||
try { | ||
(0, _child_process.execSync)("watchman --version", { | ||
stdio: ["ignore"], | ||
}); | ||
return true; | ||
} catch {} | ||
return false; | ||
})(); | ||
const WATCHMAN_REQUIRED_CAPABILITIES = [ | ||
"field-content.sha1hex", | ||
"relative_root", | ||
"suffix-set", | ||
"wildmatch", | ||
]; | ||
/** | ||
@@ -450,3 +449,3 @@ * HasteMap is a JavaScript implementation of Facebook's haste module system. | ||
async read() { | ||
var _this$_options$perfLo4, _data, _this$_options$perfLo5; | ||
var _this$_options$perfLo4, _data, _this$_options$perfLo6; | ||
@@ -461,4 +460,20 @@ let data; | ||
data = await this._cacheManager.read(); | ||
} catch {} | ||
} catch (e) { | ||
var _this$_options$perfLo5; | ||
this._console.warn( | ||
"Error while reading cache, falling back to a full crawl:\n", | ||
e | ||
); | ||
(_this$_options$perfLo5 = this._options.perfLogger) === null || | ||
_this$_options$perfLo5 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo5.annotate({ | ||
string: { | ||
cacheReadError: e.toString(), | ||
}, | ||
}); | ||
} | ||
data = | ||
@@ -468,6 +483,6 @@ (_data = data) !== null && _data !== void 0 | ||
: this._createEmptyMap(); | ||
(_this$_options$perfLo5 = this._options.perfLogger) === null || | ||
_this$_options$perfLo5 === void 0 | ||
(_this$_options$perfLo6 = this._options.perfLogger) === null || | ||
_this$_options$perfLo6 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo5.point("read_end"); | ||
: _this$_options$perfLo6.point("read_end"); | ||
return data; | ||
@@ -490,9 +505,9 @@ } | ||
async _buildFileMap() { | ||
var _this$_options$perfLo6; | ||
var _this$_options$perfLo7; | ||
let hasteMap; | ||
(_this$_options$perfLo6 = this._options.perfLogger) === null || | ||
_this$_options$perfLo6 === void 0 | ||
(_this$_options$perfLo7 = this._options.perfLogger) === null || | ||
_this$_options$perfLo7 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo6.point("buildFileMap_start"); | ||
: _this$_options$perfLo7.point("buildFileMap_start"); | ||
@@ -509,8 +524,8 @@ try { | ||
return this._crawl(hasteMap).then((result) => { | ||
var _this$_options$perfLo7; | ||
var _this$_options$perfLo8; | ||
(_this$_options$perfLo7 = this._options.perfLogger) === null || | ||
_this$_options$perfLo7 === void 0 | ||
(_this$_options$perfLo8 = this._options.perfLogger) === null || | ||
_this$_options$perfLo8 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo7.point("buildFileMap_end"); | ||
: _this$_options$perfLo8.point("buildFileMap_end"); | ||
return result; | ||
@@ -764,8 +779,8 @@ }); | ||
_buildHasteMap(data) { | ||
var _this$_options$perfLo8; | ||
var _this$_options$perfLo9; | ||
(_this$_options$perfLo8 = this._options.perfLogger) === null || | ||
_this$_options$perfLo8 === void 0 | ||
(_this$_options$perfLo9 = this._options.perfLogger) === null || | ||
_this$_options$perfLo9 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo8.point("buildHasteMap_start"); | ||
: _this$_options$perfLo9.point("buildHasteMap_start"); | ||
const { removedFiles, changedFiles, hasteMap } = data; // If any files were removed or we did not track what files changed, process | ||
@@ -820,3 +835,3 @@ // every file looking for changes. Otherwise, process only changed files. | ||
() => { | ||
var _this$_options$perfLo9; | ||
var _this$_options$perfLo10; | ||
@@ -827,6 +842,6 @@ this._cleanup(); | ||
hasteMap.mocks = mocks; | ||
(_this$_options$perfLo9 = this._options.perfLogger) === null || | ||
_this$_options$perfLo9 === void 0 | ||
(_this$_options$perfLo10 = this._options.perfLogger) === null || | ||
_this$_options$perfLo10 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo9.point("buildHasteMap_end"); | ||
: _this$_options$perfLo10.point("buildHasteMap_end"); | ||
return hasteMap; | ||
@@ -856,8 +871,8 @@ }, | ||
async _persist(hasteMap, changed, removed) { | ||
var _this$_options$perfLo10, _this$_options$perfLo11; | ||
var _this$_options$perfLo11, _this$_options$perfLo12; | ||
(_this$_options$perfLo10 = this._options.perfLogger) === null || | ||
_this$_options$perfLo10 === void 0 | ||
(_this$_options$perfLo11 = this._options.perfLogger) === null || | ||
_this$_options$perfLo11 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo10.point("persist_start"); | ||
: _this$_options$perfLo11.point("persist_start"); | ||
const snapshot = (0, _deepCloneInternalData.default)(hasteMap); | ||
@@ -868,6 +883,6 @@ await this._cacheManager.write(snapshot, { | ||
}); | ||
(_this$_options$perfLo11 = this._options.perfLogger) === null || | ||
_this$_options$perfLo11 === void 0 | ||
(_this$_options$perfLo12 = this._options.perfLogger) === null || | ||
_this$_options$perfLo12 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo11.point("persist_end"); | ||
: _this$_options$perfLo12.point("persist_end"); | ||
} | ||
@@ -897,9 +912,9 @@ /** | ||
_crawl(hasteMap) { | ||
var _this$_options$perfLo12; | ||
async _crawl(hasteMap) { | ||
var _this$_options$perfLo13; | ||
(_this$_options$perfLo12 = this._options.perfLogger) === null || | ||
_this$_options$perfLo12 === void 0 | ||
(_this$_options$perfLo13 = this._options.perfLogger) === null || | ||
_this$_options$perfLo13 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo12.point("crawl_start"); | ||
: _this$_options$perfLo13.point("crawl_start"); | ||
const options = this._options; | ||
@@ -909,4 +924,3 @@ | ||
const crawl = | ||
canUseWatchman && this._options.useWatchman ? watchmanCrawl : nodeCrawl; | ||
const crawl = (await this._shouldUseWatchman()) ? watchmanCrawl : nodeCrawl; | ||
const crawlerOptions = { | ||
@@ -950,8 +964,8 @@ abortSignal: this._crawlerAbortController.signal, | ||
const logEnd = (result) => { | ||
var _this$_options$perfLo13; | ||
var _this$_options$perfLo14; | ||
(_this$_options$perfLo13 = this._options.perfLogger) === null || | ||
_this$_options$perfLo13 === void 0 | ||
(_this$_options$perfLo14 = this._options.perfLogger) === null || | ||
_this$_options$perfLo14 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo13.point("crawl_end"); | ||
: _this$_options$perfLo14.point("crawl_end"); | ||
return result; | ||
@@ -970,18 +984,18 @@ }; | ||
_watch(hasteMap) { | ||
var _this$_options$perfLo14; | ||
async _watch(hasteMap) { | ||
var _this$_options$perfLo15, _this$_options$perfLo17; | ||
(_this$_options$perfLo14 = this._options.perfLogger) === null || | ||
_this$_options$perfLo14 === void 0 | ||
(_this$_options$perfLo15 = this._options.perfLogger) === null || | ||
_this$_options$perfLo15 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo14.point("watch_start"); | ||
: _this$_options$perfLo15.point("watch_start"); | ||
if (!this._options.watch) { | ||
var _this$_options$perfLo15; | ||
var _this$_options$perfLo16; | ||
(_this$_options$perfLo15 = this._options.perfLogger) === null || | ||
_this$_options$perfLo15 === void 0 | ||
(_this$_options$perfLo16 = this._options.perfLogger) === null || | ||
_this$_options$perfLo16 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo15.point("watch_end"); | ||
return Promise.resolve(); | ||
: _this$_options$perfLo16.point("watch_end"); | ||
return; | ||
} // In watch mode, we'll only warn about module collisions and we'll retain | ||
@@ -993,8 +1007,24 @@ // all files, even changes to node_modules. | ||
const WatcherImpl = | ||
canUseWatchman && this._options.useWatchman | ||
? _WatchmanWatcher.default | ||
: _FSEventsWatcher.default.isSupported() | ||
? _FSEventsWatcher.default | ||
: _NodeWatcher.default; | ||
const WatcherImpl = (await this._shouldUseWatchman()) | ||
? _WatchmanWatcher.default | ||
: _FSEventsWatcher.default.isSupported() | ||
? _FSEventsWatcher.default | ||
: _NodeWatcher.default; | ||
let watcher = "node"; | ||
if (WatcherImpl === _WatchmanWatcher.default) { | ||
watcher = "watchman"; | ||
} else if (WatcherImpl === _FSEventsWatcher.default) { | ||
watcher = "fsevents"; | ||
} | ||
debug(`Using watcher: ${watcher}`); | ||
(_this$_options$perfLo17 = this._options.perfLogger) === null || | ||
_this$_options$perfLo17 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo17.annotate({ | ||
string: { | ||
watcher, | ||
}, | ||
}); | ||
const extensions = this._options.extensions; | ||
@@ -1009,3 +1039,3 @@ const ignorePattern = this._options.ignorePattern; | ||
const createWatcher = (root) => { | ||
const watcher = new WatcherImpl(root, { | ||
const watcherOptions = { | ||
dot: true, | ||
@@ -1020,3 +1050,4 @@ glob: [ | ||
watchmanDeferStates: this._options.watchmanDeferStates, | ||
}); | ||
}; | ||
const watcher = new WatcherImpl(root, watcherOptions); | ||
return new Promise((resolve, reject) => { | ||
@@ -1207,11 +1238,11 @@ const rejectTimeout = setTimeout( | ||
this._changeInterval = setInterval(emitChange, CHANGE_INTERVAL); | ||
return Promise.all(this._options.roots.map(createWatcher)).then( | ||
await Promise.all(this._options.roots.map(createWatcher)).then( | ||
(watchers) => { | ||
var _this$_options$perfLo16; | ||
var _this$_options$perfLo18; | ||
this._watchers = watchers; | ||
(_this$_options$perfLo16 = this._options.perfLogger) === null || | ||
_this$_options$perfLo16 === void 0 | ||
(_this$_options$perfLo18 = this._options.perfLogger) === null || | ||
_this$_options$perfLo18 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo16.point("watch_end"); | ||
: _this$_options$perfLo18.point("watch_end"); | ||
} | ||
@@ -1310,2 +1341,37 @@ ); | ||
async _shouldUseWatchman() { | ||
if (!this._options.useWatchman) { | ||
return false; | ||
} | ||
if (!this._canUseWatchmanPromise) { | ||
this._canUseWatchmanPromise = (0, _checkWatchmanCapabilities.default)( | ||
WATCHMAN_REQUIRED_CAPABILITIES | ||
) | ||
.then(() => true) | ||
.catch((e) => { | ||
var _this$_options$perfLo19, _e$message; | ||
// TODO: Advise people to either install Watchman or set | ||
// `useWatchman: false` here? | ||
(_this$_options$perfLo19 = this._options.perfLogger) === null || | ||
_this$_options$perfLo19 === void 0 | ||
? void 0 | ||
: _this$_options$perfLo19.annotate({ | ||
string: { | ||
watchmanFailedCapabilityCheck: | ||
(_e$message = | ||
e === null || e === void 0 ? void 0 : e.message) !== | ||
null && _e$message !== void 0 | ||
? _e$message | ||
: "[missing]", | ||
}, | ||
}); | ||
return false; | ||
}); | ||
} | ||
return this._canUseWatchmanPromise; | ||
} | ||
_createEmptyMap() { | ||
@@ -1312,0 +1378,0 @@ return { |
@@ -62,2 +62,3 @@ "use strict"; | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
@@ -64,0 +65,0 @@ function moduleCacheKey(modulePath) { |
@@ -66,2 +66,3 @@ "use strict"; | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
@@ -68,0 +69,0 @@ const EMPTY_OBJ = {}; |
/** | ||
* vendored from https://github.com/amasad/sane/blob/64ff3a870c42e84f744086884bf55a4f9c22d376/src/common.js | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
/** | ||
* Originally vendored from | ||
* https://github.com/amasad/sane/blob/64ff3a870c42e84f744086884bf55a4f9c22d376/src/common.js | ||
*/ | ||
"use strict"; | ||
const anymatch = require("anymatch"); | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true, | ||
}); | ||
exports.isFileIncluded = isFileIncluded; | ||
exports.recReaddir = recReaddir; | ||
exports.assignOptions = | ||
exports.ALL_EVENT = | ||
exports.ADD_EVENT = | ||
exports.DELETE_EVENT = | ||
exports.CHANGE_EVENT = | ||
exports.DEFAULT_DELAY = | ||
void 0; | ||
// $FlowFixMe[untyped-import] - Write libdefs for `anymatch` | ||
const anymatch = require("anymatch"); // $FlowFixMe[untyped-import] - Write libdefs for `micromatch` | ||
const micromatch = require("micromatch"); | ||
@@ -13,3 +38,3 @@ | ||
const path = require("path"); | ||
const path = require("path"); // $FlowFixMe[untyped-import] - Write libdefs for `walker` | ||
@@ -21,7 +46,13 @@ const walker = require("walker"); | ||
exports.DEFAULT_DELAY = 100; | ||
exports.CHANGE_EVENT = "change"; | ||
exports.DELETE_EVENT = "delete"; | ||
exports.ADD_EVENT = "add"; | ||
exports.ALL_EVENT = "all"; | ||
const DEFAULT_DELAY = 100; | ||
exports.DEFAULT_DELAY = DEFAULT_DELAY; | ||
const CHANGE_EVENT = "change"; | ||
exports.CHANGE_EVENT = CHANGE_EVENT; | ||
const DELETE_EVENT = "delete"; | ||
exports.DELETE_EVENT = DELETE_EVENT; | ||
const ADD_EVENT = "add"; | ||
exports.ADD_EVENT = ADD_EVENT; | ||
const ALL_EVENT = "all"; | ||
exports.ALL_EVENT = ALL_EVENT; | ||
/** | ||
@@ -35,8 +66,15 @@ * Assigns options to the watcher. | ||
*/ | ||
const assignOptions = function (watcher, opts) { | ||
var _opts$glob, _opts$dot, _opts$ignored; | ||
exports.assignOptions = function (watcher, opts) { | ||
opts = opts || {}; | ||
watcher.globs = opts.glob || []; | ||
watcher.dot = opts.dot || false; | ||
watcher.ignored = opts.ignored || false; | ||
watcher.globs = | ||
(_opts$glob = opts.glob) !== null && _opts$glob !== void 0 | ||
? _opts$glob | ||
: []; | ||
watcher.dot = | ||
(_opts$dot = opts.dot) !== null && _opts$dot !== void 0 ? _opts$dot : false; | ||
watcher.ignored = | ||
(_opts$ignored = opts.ignored) !== null && _opts$ignored !== void 0 | ||
? _opts$ignored | ||
: false; | ||
watcher.watchmanDeferStates = opts.watchmanDeferStates; | ||
@@ -50,5 +88,8 @@ | ||
Boolean(opts.ignored) && !(Array.isArray(opts) && opts.length > 0); | ||
watcher.doIgnore = opts.ignored ? anymatch(opts.ignored) : () => false; | ||
watcher.doIgnore = | ||
opts.ignored != null && opts.ignored !== false | ||
? anymatch(opts.ignored) | ||
: () => false; | ||
if (opts.watchman && opts.watchmanPath) { | ||
if (opts.watchman == true && opts.watchmanPath != null) { | ||
watcher.watchmanPath = opts.watchmanPath; | ||
@@ -61,10 +102,7 @@ } | ||
* Checks a file relative path against the globs array. | ||
* | ||
* @param {array} globs | ||
* @param {string} relativePath | ||
* @return {boolean} | ||
* @public | ||
*/ | ||
exports.isFileIncluded = function (globs, dot, doIgnore, relativePath) { | ||
exports.assignOptions = assignOptions; | ||
function isFileIncluded(globs, dot, doIgnore, relativePath) { | ||
if (doIgnore(relativePath)) { | ||
@@ -79,15 +117,8 @@ return false; | ||
: dot || micromatch.some(relativePath, "**/*"); | ||
}; | ||
} | ||
/** | ||
* Traverse a directory recursively calling `callback` on every directory. | ||
* | ||
* @param {string} dir | ||
* @param {function} dirCallback | ||
* @param {function} fileCallback | ||
* @param {function} endCallback | ||
* @param {*} ignored | ||
* @public | ||
*/ | ||
exports.recReaddir = function ( | ||
function recReaddir( | ||
dir, | ||
@@ -112,10 +143,6 @@ dirCallback, | ||
}); | ||
}; | ||
} | ||
/** | ||
* Returns a callback that when called will normalize a path and call the | ||
* original callback | ||
* | ||
* @param {function} callback | ||
* @return {function} | ||
* @private | ||
*/ | ||
@@ -122,0 +149,0 @@ |
@@ -73,2 +73,3 @@ "use strict"; | ||
*/ | ||
// $FlowFixMe[cannot-resolve-module] - Optional, Darwin only | ||
// $FlowFixMe[untyped-import] - anymatch | ||
@@ -79,3 +80,4 @@ // $FlowFixMe[untyped-import] - walker | ||
// $FlowFixMe[unclear-type] - fsevents | ||
const debug = require("debug")("Metro:FSEventsWatcher"); | ||
let fsevents = null; | ||
@@ -148,6 +150,6 @@ | ||
this.root = path.resolve(dir); | ||
this.fsEventsWatchStopper = fsevents.watch( | ||
this.root, // $FlowFixMe[method-unbinding] - Refactor | ||
this._handleEvent.bind(this) | ||
this.fsEventsWatchStopper = fsevents.watch(this.root, (path) => | ||
this._handleEvent(path) | ||
); | ||
debug(`Watching ${this.root}`); | ||
this._tracked = new Set(); | ||
@@ -154,0 +156,0 @@ |
/** | ||
* vendored from https://github.com/amasad/sane/blob/64ff3a870c42e84f744086884bf55a4f9c22d376/src/node_watcher.js | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
@@ -5,0 +6,0 @@ "use strict"; |
/** | ||
* vendored from https://github.com/amasad/sane/blob/64ff3a870c42e84f744086884bf55a4f9c22d376/src/utils/recrawl-warning-dedupe.js | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
/** | ||
* Originally vendored from | ||
* https://github.com/amasad/sane/blob/64ff3a870c42e84f744086884bf55a4f9c22d376/src/utils/recrawl-warning-dedupe.js | ||
*/ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true, | ||
}); | ||
exports.default = void 0; | ||
class RecrawlWarning { | ||
static RECRAWL_WARNINGS = []; | ||
static REGEXP = | ||
/Recrawled this watch (\d+) times, most recently because:\n([^:]+)/; | ||
constructor(root, count) { | ||
@@ -57,5 +77,2 @@ this.root = root; | ||
RecrawlWarning.RECRAWL_WARNINGS = []; | ||
RecrawlWarning.REGEXP = | ||
/Recrawled this watch (\d+) times, most recently because:\n([^:]+)/; | ||
module.exports = RecrawlWarning; | ||
exports.default = RecrawlWarning; |
@@ -6,5 +6,5 @@ "use strict"; | ||
}); | ||
exports.default = WatchmanWatcher; | ||
exports.default = void 0; | ||
var _common = _interopRequireDefault(require("./common")); | ||
var common = _interopRequireWildcard(require("./common")); | ||
@@ -15,3 +15,3 @@ var _RecrawlWarning = _interopRequireDefault(require("./RecrawlWarning")); | ||
var _events = require("events"); | ||
var _events = _interopRequireDefault(require("events")); | ||
@@ -22,4 +22,10 @@ var _fbWatchman = _interopRequireDefault(require("fb-watchman")); | ||
var _invariant = _interopRequireDefault(require("invariant")); | ||
var _path = _interopRequireDefault(require("path")); | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : { default: obj }; | ||
} | ||
function _getRequireWildcardCache(nodeInterop) { | ||
@@ -67,6 +73,2 @@ if (typeof WeakMap !== "function") return null; | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : { default: obj }; | ||
} | ||
/** | ||
@@ -78,314 +80,265 @@ * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
const debug = require("debug")("Metro:WatchmanWatcher"); | ||
const CHANGE_EVENT = _common.default.CHANGE_EVENT; | ||
const DELETE_EVENT = _common.default.DELETE_EVENT; | ||
const ADD_EVENT = _common.default.ADD_EVENT; | ||
const ALL_EVENT = _common.default.ALL_EVENT; | ||
const CHANGE_EVENT = common.CHANGE_EVENT; | ||
const DELETE_EVENT = common.DELETE_EVENT; | ||
const ADD_EVENT = common.ADD_EVENT; | ||
const ALL_EVENT = common.ALL_EVENT; | ||
const SUB_NAME = "sane-sub"; | ||
/** | ||
* Watches `dir`. | ||
* | ||
* @class PollWatcher | ||
* @param String dir | ||
* @param {Object} opts | ||
* @public | ||
*/ | ||
function WatchmanWatcher(dir, opts) { | ||
_common.default.assignOptions(this, opts); | ||
class WatchmanWatcher extends _events.default { | ||
constructor(dir, opts) { | ||
super(); | ||
common.assignOptions(this, opts); | ||
this.root = _path.default.resolve(dir); | ||
this.root = _path.default.resolve(dir); | ||
this.init(); | ||
} // eslint-disable-next-line no-proto | ||
WatchmanWatcher.prototype.__proto__ = _events.EventEmitter.prototype; | ||
/** | ||
* Run the watchman `watch` command on the root and subscribe to changes. | ||
* | ||
* @private | ||
*/ | ||
WatchmanWatcher.prototype.init = function () { | ||
if (this.client) { | ||
this.client.removeAllListeners(); | ||
this._init(); | ||
} | ||
/** | ||
* Run the watchman `watch` command on the root and subscribe to changes. | ||
*/ | ||
const self = this; | ||
this.client = new _fbWatchman.default.Client(); | ||
this.client.on("error", (error) => { | ||
self.emit("error", error); | ||
}); | ||
this.client.on("subscription", this.handleChangeEvent.bind(this)); | ||
this.client.on("end", () => { | ||
console.warn("[sane] Warning: Lost connection to watchman, reconnecting.."); | ||
self.init(); | ||
}); | ||
this.watchProjectInfo = null; | ||
function getWatchRoot() { | ||
return self.watchProjectInfo ? self.watchProjectInfo.root : self.root; | ||
} | ||
function onCapability(error, resp) { | ||
if (handleError(self, error)) { | ||
// The Watchman watcher is unusable on this system, we cannot continue | ||
return; | ||
_init() { | ||
if (this.client) { | ||
this.client.removeAllListeners(); | ||
} | ||
handleWarning(resp); | ||
self.capabilities = resp.capabilities; | ||
const self = this; | ||
this.client = new _fbWatchman.default.Client(); | ||
this.client.on("error", (error) => { | ||
self.emit("error", error); | ||
}); | ||
this.client.on("subscription", (changeEvent) => | ||
this._handleChangeEvent(changeEvent) | ||
); | ||
this.client.on("end", () => { | ||
console.warn( | ||
"[metro-file-map] Warning: Lost connection to Watchman, reconnecting.." | ||
); | ||
if (self.capabilities.relative_root) { | ||
self.client.command(["watch-project", getWatchRoot()], onWatchProject); | ||
} else { | ||
self.client.command(["watch", getWatchRoot()], onWatch); | ||
} | ||
} | ||
self._init(); | ||
}); | ||
this.watchProjectInfo = null; | ||
function onWatchProject(error, resp) { | ||
if (handleError(self, error)) { | ||
return; | ||
function getWatchRoot() { | ||
return self.watchProjectInfo ? self.watchProjectInfo.root : self.root; | ||
} | ||
handleWarning(resp); | ||
self.watchProjectInfo = { | ||
relativePath: resp.relative_path ? resp.relative_path : "", | ||
root: resp.watch, | ||
}; | ||
self.client.command(["clock", getWatchRoot()], onClock); | ||
} | ||
function onWatchProject(error, resp) { | ||
if (handleError(self, error)) { | ||
return; | ||
} | ||
function onWatch(error, resp) { | ||
if (handleError(self, error)) { | ||
return; | ||
debug("Received watch-project response: %s", resp.relative_path); | ||
handleWarning(resp); | ||
self.watchProjectInfo = { | ||
relativePath: resp.relative_path ? resp.relative_path : "", | ||
root: resp.watch, | ||
}; | ||
self.client.command(["clock", getWatchRoot()], onClock); | ||
} | ||
handleWarning(resp); | ||
self.client.command(["clock", getWatchRoot()], onClock); | ||
} | ||
function onClock(error, resp) { | ||
if (handleError(self, error)) { | ||
return; | ||
} | ||
function onClock(error, resp) { | ||
if (handleError(self, error)) { | ||
return; | ||
} | ||
debug("Received clock response: %s", resp.clock); | ||
const watchProjectInfo = self.watchProjectInfo; | ||
(0, _invariant.default)( | ||
watchProjectInfo != null, | ||
"watch-project response should have been set before clock response" | ||
); | ||
handleWarning(resp); | ||
const options = { | ||
fields: ["name", "exists", "new"], | ||
since: resp.clock, | ||
defer: self.watchmanDeferStates, | ||
relative_root: watchProjectInfo.relativePath, | ||
}; // Make sure we honor the dot option if even we're not using globs. | ||
handleWarning(resp); | ||
const options = { | ||
fields: ["name", "exists", "new"], | ||
since: resp.clock, | ||
defer: self.watchmanDeferStates, | ||
}; // If the server has the wildmatch capability available it supports | ||
// the recursive **/*.foo style match and we can offload our globs | ||
// to the watchman server. This saves both on data size to be | ||
// communicated back to us and compute for evaluating the globs | ||
// in our node process. | ||
if (self.globs.length === 0 && !self.dot) { | ||
options.expression = [ | ||
"match", | ||
"**", | ||
"wholename", | ||
{ | ||
includedotfiles: false, | ||
}, | ||
]; | ||
} | ||
if (self.capabilities.wildmatch) { | ||
if (self.globs.length === 0) { | ||
if (!self.dot) { | ||
// Make sure we honor the dot option if even we're not using globs. | ||
options.expression = [ | ||
"match", | ||
"**", | ||
"wholename", | ||
{ | ||
includedotfiles: false, | ||
}, | ||
]; | ||
} | ||
} else { | ||
options.expression = ["anyof"]; | ||
self.client.command( | ||
["subscribe", getWatchRoot(), SUB_NAME, options], | ||
onSubscribe | ||
); | ||
} | ||
for (const i in self.globs) { | ||
options.expression.push([ | ||
"match", | ||
self.globs[i], | ||
"wholename", | ||
{ | ||
includedotfiles: self.dot, | ||
}, | ||
]); | ||
} | ||
function onSubscribe(error, resp) { | ||
if (handleError(self, error)) { | ||
return; | ||
} | ||
} | ||
if (self.capabilities.relative_root) { | ||
options.relative_root = self.watchProjectInfo.relativePath; | ||
debug("Received subscribe response: %s", resp.subscribe); | ||
handleWarning(resp); | ||
self.emit("ready"); | ||
} | ||
self.client.command( | ||
["subscribe", getWatchRoot(), SUB_NAME, options], | ||
onSubscribe | ||
); | ||
self.client.command(["watch-project", getWatchRoot()], onWatchProject); | ||
} | ||
/** | ||
* Handles a change event coming from the subscription. | ||
*/ | ||
function onSubscribe(error, resp) { | ||
if (handleError(self, error)) { | ||
return; | ||
} | ||
_handleChangeEvent(resp) { | ||
var _resp$files, _this$watchmanDeferSt, _this$watchmanDeferSt2; | ||
handleWarning(resp); | ||
self.emit("ready"); | ||
} | ||
debug( | ||
"Received subscription response: %s (fresh: %s}, files: %s, enter: %s, leave: %s)", | ||
resp.subscription, | ||
resp.is_fresh_instance, | ||
(_resp$files = resp.files) === null || _resp$files === void 0 | ||
? void 0 | ||
: _resp$files.length, | ||
resp["state-enter"], | ||
resp["state-leave"] | ||
); | ||
self.client.capabilityCheck( | ||
{ | ||
optional: ["wildmatch", "relative_root"], | ||
}, | ||
onCapability | ||
); | ||
}; | ||
/** | ||
* Handles a change event coming from the subscription. | ||
* | ||
* @param {Object} resp | ||
* @private | ||
*/ | ||
_assert.default.equal( | ||
resp.subscription, | ||
SUB_NAME, | ||
"Invalid subscription event." | ||
); | ||
WatchmanWatcher.prototype.handleChangeEvent = function (resp) { | ||
var _this$watchmanDeferSt, _this$watchmanDeferSt2; | ||
if (resp.is_fresh_instance) { | ||
this.emit("fresh_instance"); | ||
} | ||
_assert.default.equal( | ||
resp.subscription, | ||
SUB_NAME, | ||
"Invalid subscription event." | ||
); | ||
if (resp.is_fresh_instance) { | ||
this.emit("fresh_instance"); | ||
} | ||
if (resp.is_fresh_instance) { | ||
this.emit("fresh_instance"); | ||
} | ||
if (Array.isArray(resp.files)) { | ||
resp.files.forEach((change) => this._handleFileChange(change)); | ||
} | ||
if (resp.is_fresh_instance) { | ||
this.emit("fresh_instance"); | ||
} | ||
if ( | ||
resp["state-enter"] != null && | ||
((_this$watchmanDeferSt = this.watchmanDeferStates) !== null && | ||
_this$watchmanDeferSt !== void 0 | ||
? _this$watchmanDeferSt | ||
: [] | ||
).includes(resp["state-enter"]) | ||
) { | ||
debug( | ||
'Watchman reports "%s" just started. Filesystem notifications are paused.', | ||
resp["state-enter"] | ||
); | ||
} | ||
if (Array.isArray(resp.files)) { | ||
resp.files.forEach(this.handleFileChange, this); | ||
if ( | ||
resp["state-leave"] != null && | ||
((_this$watchmanDeferSt2 = this.watchmanDeferStates) !== null && | ||
_this$watchmanDeferSt2 !== void 0 | ||
? _this$watchmanDeferSt2 | ||
: [] | ||
).includes(resp["state-leave"]) | ||
) { | ||
debug( | ||
'Watchman reports "%s" ended. Filesystem notifications resumed.', | ||
resp["state-leave"] | ||
); | ||
} | ||
} | ||
/** | ||
* Handles a single change event record. | ||
*/ | ||
if ( | ||
((_this$watchmanDeferSt = this.watchmanDeferStates) !== null && | ||
_this$watchmanDeferSt !== void 0 | ||
? _this$watchmanDeferSt | ||
: [] | ||
).includes(resp["state-enter"]) | ||
) { | ||
debug( | ||
`Watchman reports ${resp["state-enter"]} just started. Filesystem notifications are paused.` | ||
_handleFileChange(changeDescriptor) { | ||
const self = this; | ||
const watchProjectInfo = self.watchProjectInfo; | ||
(0, _invariant.default)( | ||
watchProjectInfo != null, | ||
"watch-project response should have been set before receiving subscription events" | ||
); | ||
} | ||
if ( | ||
((_this$watchmanDeferSt2 = this.watchmanDeferStates) !== null && | ||
_this$watchmanDeferSt2 !== void 0 | ||
? _this$watchmanDeferSt2 | ||
: [] | ||
).includes(resp["state-leave"]) | ||
) { | ||
const { | ||
name: relativePath, | ||
new: isNew = false, | ||
exists = false, | ||
} = changeDescriptor; | ||
debug( | ||
`Watchman reports ${resp["state-leave"]} ended. Filesystem notifications resumed.` | ||
"Handling change to: %s (new: %s, exists: %s)", | ||
relativePath, | ||
isNew, | ||
exists | ||
); | ||
} | ||
}; | ||
/** | ||
* Handles a single change event record. | ||
* | ||
* @param {Object} changeDescriptor | ||
* @private | ||
*/ | ||
WatchmanWatcher.prototype.handleFileChange = function (changeDescriptor) { | ||
const self = this; | ||
let absPath; | ||
let relativePath; | ||
if (this.capabilities.relative_root) { | ||
relativePath = changeDescriptor.name; | ||
absPath = _path.default.join( | ||
this.watchProjectInfo.root, | ||
this.watchProjectInfo.relativePath, | ||
const absPath = _path.default.join( | ||
watchProjectInfo.root, | ||
watchProjectInfo.relativePath, | ||
relativePath | ||
); | ||
} else { | ||
absPath = _path.default.join(this.root, changeDescriptor.name); | ||
relativePath = changeDescriptor.name; | ||
} | ||
if ( | ||
!(self.capabilities.wildmatch && !this.hasIgnore) && | ||
!_common.default.isFileIncluded( | ||
this.globs, | ||
this.dot, | ||
this.doIgnore, | ||
relativePath | ||
) | ||
) { | ||
return; | ||
} | ||
if ( | ||
this.hasIgnore && | ||
!common.isFileIncluded(this.globs, this.dot, this.doIgnore, relativePath) | ||
) { | ||
return; | ||
} | ||
if (!changeDescriptor.exists) { | ||
self.emitEvent(DELETE_EVENT, relativePath, self.root); | ||
} else { | ||
fs.lstat(absPath, (error, stat) => { | ||
// Files can be deleted between the event and the lstat call | ||
// the most reliable thing to do here is to ignore the event. | ||
if (error && error.code === "ENOENT") { | ||
return; | ||
} | ||
if (!exists) { | ||
self._emitEvent(DELETE_EVENT, relativePath, self.root); | ||
} else { | ||
fs.lstat(absPath, (error, stat) => { | ||
// Files can be deleted between the event and the lstat call | ||
// the most reliable thing to do here is to ignore the event. | ||
if (error && error.code === "ENOENT") { | ||
return; | ||
} | ||
if (handleError(self, error)) { | ||
return; | ||
} | ||
if (handleError(self, error)) { | ||
return; | ||
} | ||
const eventType = changeDescriptor.new ? ADD_EVENT : CHANGE_EVENT; // Change event on dirs are mostly useless. | ||
const eventType = isNew ? ADD_EVENT : CHANGE_EVENT; // Change event on dirs are mostly useless. | ||
if (!(eventType === CHANGE_EVENT && stat.isDirectory())) { | ||
self.emitEvent(eventType, relativePath, self.root, stat); | ||
} | ||
}); | ||
if (!(eventType === CHANGE_EVENT && stat.isDirectory())) { | ||
self._emitEvent(eventType, relativePath, self.root, stat); | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
/** | ||
* Dispatches the event. | ||
* | ||
* @param {string} eventType | ||
* @param {string} filepath | ||
* @param {string} root | ||
* @param {fs.Stat} stat | ||
* @private | ||
*/ | ||
/** | ||
* Dispatches the event. | ||
*/ | ||
WatchmanWatcher.prototype.emitEvent = function ( | ||
eventType, | ||
filepath, | ||
root, | ||
stat | ||
) { | ||
this.emit(eventType, filepath, root, stat); | ||
this.emit(ALL_EVENT, eventType, filepath, root, stat); | ||
}; | ||
/** | ||
* Closes the watcher. | ||
* | ||
*/ | ||
_emitEvent(eventType, filepath, root, stat) { | ||
this.emit(eventType, filepath, root, stat); | ||
this.emit(ALL_EVENT, eventType, filepath, root, stat); | ||
} | ||
/** | ||
* Closes the watcher. | ||
*/ | ||
WatchmanWatcher.prototype.close = function () { | ||
this.client.removeAllListeners(); | ||
this.client.end(); | ||
return Promise.resolve(); | ||
}; | ||
async close() { | ||
this.client.removeAllListeners(); | ||
this.client.end(); | ||
} | ||
} | ||
/** | ||
* Handles an error and returns true if exists. | ||
* | ||
* @param {WatchmanWatcher} self | ||
* @param {Error} error | ||
* @private | ||
*/ | ||
function handleError(self, error) { | ||
exports.default = WatchmanWatcher; | ||
function handleError(emitter, error) { | ||
if (error != null) { | ||
self.emit("error", error); | ||
emitter.emit("error", error); | ||
return true; | ||
@@ -398,5 +351,2 @@ } else { | ||
* Handles a warning in the watchman resp object. | ||
* | ||
* @param {object} resp | ||
* @private | ||
*/ | ||
@@ -403,0 +353,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
247918
49
4246