Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

metro-file-map

Package Overview
Dependencies
Maintainers
2
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

metro-file-map - npm Package Compare versions

Comparing version 0.73.2 to 0.73.3

src/watchers/NodeWatcher.js.flow

3

package.json
{
"name": "metro-file-map",
"version": "0.73.2",
"version": "0.73.3",
"description": "[Experimental] - 🚇 File crawling, watching and mapping for Metro",

@@ -27,2 +27,3 @@ "main": "src/index.js",

"micromatch": "^4.0.4",
"nullthrows": "^1.1.1",
"walker": "^1.0.7"

@@ -29,0 +30,0 @@ },

@@ -296,2 +296,3 @@ "use strict";

...buildParameters,
healthCheck: options.healthCheck,
maxWorkers: options.maxWorkers,

@@ -517,2 +518,3 @@ perfLogger: options.perfLogger,

forceNodeFilesystemAPI,
healthCheckFilePrefix: this._options.healthCheck.filePrefix,
ignore: (path) => this._ignore(path),

@@ -1119,2 +1121,23 @@ ignorePattern,

await this._watcher.watch(onChange);
if (this._options.healthCheck.enabled) {
const performHealthCheck = () => {
if (!this._watcher) {
return;
}
this._watcher
.checkHealth(this._options.healthCheck.timeout)
.then((result) => {
this.emit("healthCheck", result);
});
};
performHealthCheck();
this._healthCheckInterval = setInterval(
performHealthCheck,
this._options.healthCheck.interval
);
}
(_this$_options$perfLo15 = this._options.perfLogger) === null ||

@@ -1190,2 +1213,6 @@ _this$_options$perfLo15 === void 0

if (this._healthCheckInterval) {
clearInterval(this._healthCheckInterval);
}
if (!this._watcher) {

@@ -1192,0 +1219,0 @@ return;

@@ -22,2 +22,54 @@ "use strict";

var path = _interopRequireWildcard(require("path"));
var fs = _interopRequireWildcard(require("fs"));
var _common = require("./watchers/common");
var _perf_hooks = require("perf_hooks");
var _nullthrows = _interopRequireDefault(require("nullthrows"));
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;
}
function _interopRequireDefault(obj) {

@@ -40,8 +92,12 @@ return obj && obj.__esModule ? obj : { default: obj };

const MAX_WAIT_TIME = 240000;
let nextInstanceId = 0;
class Watcher {
_backends = [];
_nextHealthCheckId = 0;
_pendingHealthChecks = new Map();
constructor(options) {
this._options = options;
this._instanceId = nextInstanceId++;
}

@@ -58,3 +114,5 @@

const ignore = (filePath) => options.ignore(filePath);
const ignore = (filePath) =>
options.ignore(filePath) ||
path.basename(filePath).startsWith(this._options.healthCheckFilePrefix);

@@ -142,2 +200,3 @@ const crawl = options.useWatchman ? _watchman.default : _node.default;

});
this._activeWatcher = watcher;

@@ -150,3 +209,4 @@ const createWatcherBackend = (root) => {

/// module resolution.
"**/package.json",
"**/package.json", // Ensure we always watch any health check files
"**/" + this._options.healthCheckFilePrefix + "*",
...extensions.map((extension) => "**/*." + extension),

@@ -165,3 +225,21 @@ ],

clearTimeout(rejectTimeout);
watcher.on("all", onChange);
watcher.on("all", (type, filePath, root, stat) => {
const basename = path.basename(filePath);
if (basename.startsWith(this._options.healthCheckFilePrefix)) {
if (type === _common.ADD_EVENT || type === _common.CHANGE_EVENT) {
debug(
"Observed possible health check cookie: %s in %s",
filePath,
root
);
this._handleHealthCheckObservation(basename);
}
return;
}
onChange(type, filePath, root, stat);
});
resolve(watcher);

@@ -177,7 +255,97 @@ });

_handleHealthCheckObservation(basename) {
const resolveHealthCheck = this._pendingHealthChecks.get(basename);
if (!resolveHealthCheck) {
return;
}
resolveHealthCheck();
}
async close() {
await Promise.all(this._backends.map((watcher) => watcher.close()));
this._activeWatcher = null;
}
async checkHealth(timeout) {
const healthCheckId = this._nextHealthCheckId++;
if (healthCheckId === Number.MAX_SAFE_INTEGER) {
this._nextHealthCheckId = 0;
}
const watcher = this._activeWatcher;
const basename =
this._options.healthCheckFilePrefix +
"-" +
process.pid +
"-" +
this._instanceId +
"-" +
healthCheckId;
const healthCheckPath = path.join(this._options.rootDir, basename);
let result;
const timeoutPromise = new Promise((resolve) =>
setTimeout(resolve, timeout)
).then(() => {
if (!result) {
var _this$_backends$;
result = {
type: "timeout",
pauseReason:
(_this$_backends$ = this._backends[0]) === null ||
_this$_backends$ === void 0
? void 0
: _this$_backends$.getPauseReason(),
timeout,
watcher,
};
}
});
const startTime = _perf_hooks.performance.now();
debug("Creating health check cookie: %s", healthCheckPath);
const creationPromise = fs.promises
.writeFile(healthCheckPath, String(startTime))
.catch((error) => {
if (!result) {
result = {
type: "error",
error,
timeout,
watcher,
};
}
});
const observationPromise = new Promise((resolve) => {
this._pendingHealthChecks.set(basename, resolve);
}).then(() => {
if (!result) {
result = {
type: "success",
timeElapsed: _perf_hooks.performance.now() - startTime,
timeout,
watcher,
};
}
});
await Promise.race([
timeoutPromise,
creationPromise.then(() => observationPromise),
]);
this._pendingHealthChecks.delete(basename); // Chain a deletion to the creation promise (which may not have even settled yet!),
// don't await it, and swallow errors. This is just best-effort cleanup.
creationPromise.then(() =>
fs.promises.unlink(healthCheckPath).catch(() => {})
);
debug("Health check result: %o", result);
return (0, _nullthrows.default)(result);
}
}
exports.Watcher = Watcher;

@@ -236,4 +236,8 @@ "use strict";

}
getPauseReason() {
return null;
}
}
exports.default = FSEventsWatcher;
/**
* vendored from https://github.com/amasad/sane/blob/64ff3a870c42e84f744086884bf55a4f9c22d376/src/node_watcher.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/node_watcher.js
*/
"use strict";

@@ -10,3 +19,3 @@

const EventEmitter = require("events").EventEmitter;
const { EventEmitter } = require("events");

@@ -18,5 +27,2 @@ const fs = require("fs");

const path = require("path");
/**
* Constants
*/

@@ -28,12 +34,2 @@ const DEFAULT_DELAY = common.DEFAULT_DELAY;

const ALL_EVENT = common.ALL_EVENT;
/**
* Export `NodeWatcher` class.
* Watches `dir`.
*
* @class NodeWatcher
* @param {String} dir
* @param {Object} opts
* @public
*/
module.exports = class NodeWatcher extends EventEmitter {

@@ -44,15 +40,18 @@ constructor(dir, opts) {

this.watched = Object.create(null);
this.changeTimers = Object.create(null);
this.dirRegistery = Object.create(null);
this._changeTimers = Object.create(null);
this._dirRegistry = Object.create(null);
this.root = path.resolve(dir);
this.watchdir = this.watchdir.bind(this);
this.register = this.register.bind(this);
this.checkedEmitError = this.checkedEmitError.bind(this);
this.watchdir(this.root);
this._watchdir(this.root);
common.recReaddir(
this.root,
this.watchdir,
this.register,
this.emit.bind(this, "ready"),
this.checkedEmitError,
this._watchdir,
(filename) => {
this._register(filename);
},
() => {
this.emit("ready");
},
this._checkedEmitError,
this.ignored

@@ -65,3 +64,3 @@ );

*
* Registery looks like the following:
* Registry looks like the following:
*

@@ -73,9 +72,5 @@ * dirRegister => Map {

* }
*
* @param {string} filepath
* @return {boolean} whether or not we have registered the file.
* @private
*/
register(filepath) {
_register(filepath) {
const relativePath = path.relative(this.root, filepath);

@@ -91,51 +86,41 @@

if (!this.dirRegistery[dir]) {
this.dirRegistery[dir] = Object.create(null);
if (!this._dirRegistry[dir]) {
this._dirRegistry[dir] = Object.create(null);
}
const filename = path.basename(filepath);
this.dirRegistery[dir][filename] = true;
this._dirRegistry[dir][filename] = true;
return true;
}
/**
* Removes a file from the registery.
*
* @param {string} filepath
* @private
* Removes a file from the registry.
*/
unregister(filepath) {
_unregister(filepath) {
const dir = path.dirname(filepath);
if (this.dirRegistery[dir]) {
if (this._dirRegistry[dir]) {
const filename = path.basename(filepath);
delete this.dirRegistery[dir][filename];
delete this._dirRegistry[dir][filename];
}
}
/**
* Removes a dir from the registery.
*
* @param {string} dirpath
* @private
* Removes a dir from the registry.
*/
unregisterDir(dirpath) {
if (this.dirRegistery[dirpath]) {
delete this.dirRegistery[dirpath];
_unregisterDir(dirpath) {
if (this._dirRegistry[dirpath]) {
delete this._dirRegistry[dirpath];
}
}
/**
* Checks if a file or directory exists in the registery.
*
* @param {string} fullpath
* @return {boolean}
* @private
* Checks if a file or directory exists in the registry.
*/
registered(fullpath) {
_registered(fullpath) {
const dir = path.dirname(fullpath);
return (
this.dirRegistery[fullpath] ||
(this.dirRegistery[dir] &&
this.dirRegistery[dir][path.basename(fullpath)])
return !!(
this._dirRegistry[fullpath] ||
(this._dirRegistry[dir] &&
this._dirRegistry[dir][path.basename(fullpath)])
);

@@ -145,20 +130,14 @@ }

* Emit "error" event if it's not an ignorable event
*
* @param error
* @private
*/
checkedEmitError(error) {
_checkedEmitError = (error) => {
if (!isIgnorableFileError(error)) {
this.emit("error", error);
}
}
};
/**
* Watch a directory.
*
* @param {string} dir
* @private
*/
watchdir(dir) {
_watchdir = (dir) => {
if (this.watched[dir]) {

@@ -173,19 +152,16 @@ return;

},
this.normalizeChange.bind(this, dir)
(event, filename) => this._normalizeChange(dir, event, filename)
);
this.watched[dir] = watcher;
watcher.on("error", this.checkedEmitError);
watcher.on("error", this._checkedEmitError);
if (this.root !== dir) {
this.register(dir);
this._register(dir);
}
}
};
/**
* Stop watching a directory.
*
* @param {string} dir
* @private
*/
stopWatching(dir) {
_stopWatching(dir) {
if (this.watched[dir]) {

@@ -198,10 +174,7 @@ this.watched[dir].close();

* End watching.
*
* @public
*/
close() {
Object.keys(this.watched).forEach(this.stopWatching, this);
async close() {
Object.keys(this.watched).forEach((dir) => this._stopWatching(dir));
this.removeAllListeners();
return Promise.resolve();
}

@@ -212,11 +185,6 @@ /**

* change by detecting if something was deleted or the most recent file change.
*
* @param {string} dir
* @param {string} event
* @param {string} file
* @public
*/
detectChangedFile(dir, event, callback) {
if (!this.dirRegistery[dir]) {
_detectChangedFile(dir, event, callback) {
if (!this._dirRegistry[dir]) {
return;

@@ -226,7 +194,5 @@ }

let found = false;
let closest = {
mtime: 0,
};
let closest = null;
let c = 0;
Object.keys(this.dirRegistery[dir]).forEach(function (file, i, arr) {
Object.keys(this._dirRegistry[dir]).forEach((file, i, arr) => {
fs.lstat(path.join(dir, file), (error, stat) => {

@@ -245,5 +211,7 @@ if (found) {

} else {
if (stat.mtime > closest.mtime) {
stat.file = file;
closest = stat;
if (closest == null || stat.mtime > closest.mtime) {
closest = {
file,
mtime: stat.mtime,
};
}

@@ -256,22 +224,17 @@

});
}, this);
});
}
/**
* Normalize fs events and pass it on to be processed.
*
* @param {string} dir
* @param {string} event
* @param {string} file
* @public
*/
normalizeChange(dir, event, file) {
_normalizeChange(dir, event, file) {
if (!file) {
this.detectChangedFile(dir, event, (actualFile) => {
this._detectChangedFile(dir, event, (actualFile) => {
if (actualFile) {
this.processChange(dir, event, actualFile);
this._processChange(dir, event, actualFile);
}
});
} else {
this.processChange(dir, event, path.normalize(file));
this._processChange(dir, event, path.normalize(file));
}

@@ -281,10 +244,5 @@ }

* Process changes.
*
* @param {string} dir
* @param {string} event
* @param {string} file
* @public
*/
processChange(dir, event, file) {
_processChange(dir, event, file) {
const fullPath = path.join(dir, file);

@@ -298,3 +256,3 @@ const relativePath = path.join(path.relative(this.root, dir), file);

if (event !== "change") {
this.watchdir(fullPath);
this._watchdir(fullPath);

@@ -309,21 +267,23 @@ if (

) {
this.emitEvent(ADD_EVENT, relativePath, stat);
this._emitEvent(ADD_EVENT, relativePath, stat);
}
}
} else {
const registered = this.registered(fullPath);
const registered = this._registered(fullPath);
if (error && error.code === "ENOENT") {
this.unregister(fullPath);
this.stopWatching(fullPath);
this.unregisterDir(fullPath);
this._unregister(fullPath);
this._stopWatching(fullPath);
this._unregisterDir(fullPath);
if (registered) {
this.emitEvent(DELETE_EVENT, relativePath);
this._emitEvent(DELETE_EVENT, relativePath);
}
} else if (registered) {
this.emitEvent(CHANGE_EVENT, relativePath, stat);
this._emitEvent(CHANGE_EVENT, relativePath, stat);
} else {
if (this.register(fullPath)) {
this.emitEvent(ADD_EVENT, relativePath, stat);
if (this._register(fullPath)) {
this._emitEvent(ADD_EVENT, relativePath, stat);
}

@@ -337,11 +297,9 @@ }

* events on os x.
*
* @private
*/
emitEvent(type, file, stat) {
_emitEvent(type, file, stat) {
const key = type + "-" + file;
const addKey = ADD_EVENT + "-" + file;
if (type === CHANGE_EVENT && this.changeTimers[addKey]) {
if (type === CHANGE_EVENT && this._changeTimers[addKey]) {
// Ignore the change event that is immediately fired after an add event.

@@ -352,24 +310,35 @@ // (This happens on Linux).

clearTimeout(this.changeTimers[key]);
this.changeTimers[key] = setTimeout(() => {
delete this.changeTimers[key];
clearTimeout(this._changeTimers[key]);
this._changeTimers[key] = setTimeout(() => {
delete this._changeTimers[key];
if (type === ADD_EVENT && stat.isDirectory()) {
if (
type === ADD_EVENT &&
stat !== null &&
stat !== void 0 &&
stat.isDirectory()
) {
// Recursively emit add events and watch for sub-files/folders
common.recReaddir(
path.resolve(this.root, file),
function emitAddDir(dir, stats) {
this.watchdir(dir);
this.rawEmitEvent(ADD_EVENT, path.relative(this.root, dir), stats);
}.bind(this),
function emitAddFile(file, stats) {
this.register(file);
this.rawEmitEvent(ADD_EVENT, path.relative(this.root, file), stats);
}.bind(this),
(dir, stats) => {
this._watchdir(dir);
this._rawEmitEvent(ADD_EVENT, path.relative(this.root, dir), stats);
},
(file, stats) => {
this._register(file);
this._rawEmitEvent(
ADD_EVENT,
path.relative(this.root, file),
stats
);
},
function endCallback() {},
this.checkedEmitError,
this._checkedEmitError,
this.ignored
);
} else {
this.rawEmitEvent(type, file, stat);
this._rawEmitEvent(type, file, stat);
}

@@ -382,11 +351,13 @@ }, DEFAULT_DELAY);

rawEmitEvent(type, file, stat) {
_rawEmitEvent(type, file, stat) {
this.emit(type, file, this.root, stat);
this.emit(ALL_EVENT, type, file, this.root, stat);
}
getPauseReason() {
return null;
}
};
/**
* Determine if a given FS error can be ignored
*
* @private
*/

@@ -393,0 +364,0 @@

@@ -94,2 +94,4 @@ "use strict";

class WatchmanWatcher extends _events.default {
#deferringStates = new Set();
constructor(dir, opts) {

@@ -191,3 +193,3 @@ super();

function onSubscribe(error, resp) {
const onSubscribe = (error, resp) => {
if (handleError(self, error)) {

@@ -199,4 +201,9 @@ return;

handleWarning(resp);
for (const state of resp["asserted-states"]) {
this.#deferringStates.add(state);
}
self.emit("ready");
}
};

@@ -241,4 +248,6 @@ self.client.command(["watch-project", getWatchRoot()], onWatchProject);

const { "state-enter": stateEnter, "state-leave": stateLeave } = resp;
if (
resp["state-enter"] != null &&
stateEnter != null &&
((_this$watchmanDeferSt = this.watchmanDeferStates) !== null &&

@@ -248,7 +257,8 @@ _this$watchmanDeferSt !== void 0

: []
).includes(resp["state-enter"])
).includes(stateEnter)
) {
this.#deferringStates.add(stateEnter);
debug(
'Watchman reports "%s" just started. Filesystem notifications are paused.',
resp["state-enter"]
stateEnter
);

@@ -258,3 +268,3 @@ }

if (
resp["state-leave"] != null &&
stateLeave != null &&
((_this$watchmanDeferSt2 = this.watchmanDeferStates) !== null &&

@@ -264,7 +274,8 @@ _this$watchmanDeferSt2 !== void 0

: []
).includes(resp["state-leave"])
).includes(stateLeave)
) {
this.#deferringStates.delete(stateLeave);
debug(
'Watchman reports "%s" ended. Filesystem notifications resumed.',
resp["state-leave"]
stateLeave
);

@@ -346,3 +357,21 @@ }

this.client.end();
this.#deferringStates.clear();
}
getPauseReason() {
if (this.#deferringStates.size) {
const states = [...this.#deferringStates];
if (states.length === 1) {
return `The watch is in the '${states[0]}' state.`;
}
return `The watch is in the ${states
.slice(0, -1)
.map((s) => `'${s}'`)
.join(", ")} and '${states[states.length - 1]}' states.`;
}
return null;
}
}

@@ -349,0 +378,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

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc