UNPKG

atom-nuclide

Version:

A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.

163 lines (135 loc) 5.84 kB
Object.defineProperty(exports, '__esModule', { value: true }); /* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ exports.watchFile = watchFile; exports.watchDirectory = watchDirectory; var getRealPath = _asyncToGenerator(function* (entityPath, isFile) { var stat = undefined; try { stat = yield (_commonsNodeFsPromise2 || _commonsNodeFsPromise()).default.stat(entityPath); } catch (e) { // Atom watcher behavior compatibility. throw new Error('Can\'t watch a non-existing entity: ' + entityPath); } if (stat.isFile() !== isFile) { (0, (_nuclideLogging2 || _nuclideLogging()).getLogger)().warn('FileWatcherService: expected ' + entityPath + ' to be a ' + (isFile ? 'file' : 'directory')); } return yield (_commonsNodeFsPromise2 || _commonsNodeFsPromise()).default.realpath(entityPath); }); exports.watchDirectoryRecursive = watchDirectoryRecursive; var unwatchDirectoryRecursive = _asyncToGenerator(function* (directoryPath) { yield getWatchmanClient().unwatch(directoryPath); }); function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { var callNext = step.bind(null, 'next'); var callThrow = step.bind(null, 'throw'); function step(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(callNext, callThrow); } } callNext(); }); }; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var _commonsNodeNuclideUri2; function _commonsNodeNuclideUri() { return _commonsNodeNuclideUri2 = _interopRequireDefault(require('../../commons-node/nuclideUri')); } var _rxjsBundlesRxUmdMinJs2; function _rxjsBundlesRxUmdMinJs() { return _rxjsBundlesRxUmdMinJs2 = require('rxjs/bundles/Rx.umd.min.js'); } var _commonsNodeFsPromise2; function _commonsNodeFsPromise() { return _commonsNodeFsPromise2 = _interopRequireDefault(require('../../commons-node/fsPromise')); } var _nuclideLogging2; function _nuclideLogging() { return _nuclideLogging2 = require('../../nuclide-logging'); } var _nuclideWatchmanHelpers2; function _nuclideWatchmanHelpers() { return _nuclideWatchmanHelpers2 = require('../../nuclide-watchman-helpers'); } // Cache an observable for each watched entity (file or directory). // Multiple watches for the same entity can share the same observable. var entityObservable = new Map(); // In addition, expose the observer behind each observable so we can // dispatch events from the root subscription. var entityObserver = new Map(); var watchmanClient = null; function getWatchmanClient() { if (watchmanClient == null) { watchmanClient = new (_nuclideWatchmanHelpers2 || _nuclideWatchmanHelpers()).WatchmanClient(); } return watchmanClient; } function watchFile(filePath) { return watchEntity(filePath, true).publish(); } function watchDirectory(directoryPath) { return watchEntity(directoryPath, false).publish(); } function watchEntity(entityPath, isFile) { return (_rxjsBundlesRxUmdMinJs2 || _rxjsBundlesRxUmdMinJs()).Observable.fromPromise(getRealPath(entityPath, isFile)).flatMap(function (realPath) { var observable = entityObservable.get(realPath); if (observable != null) { return observable; } observable = (_rxjsBundlesRxUmdMinJs2 || _rxjsBundlesRxUmdMinJs()).Observable.create(function (observer) { entityObserver.set(realPath, observer); return function () { entityObserver.delete(realPath); entityObservable.delete(realPath); }; }).map(function (type) { return { path: realPath, type: type }; }).share(); entityObservable.set(realPath, observable); return observable; }); } function watchDirectoryRecursive(directoryPath) { var client = getWatchmanClient(); if (client.hasSubscription(directoryPath)) { return (_rxjsBundlesRxUmdMinJs2 || _rxjsBundlesRxUmdMinJs()).Observable.of('EXISTING').publish(); } return (_rxjsBundlesRxUmdMinJs2 || _rxjsBundlesRxUmdMinJs()).Observable.fromPromise(client.watchDirectoryRecursive(directoryPath)).flatMap(function (watcher) { // Listen for watcher changes to route them to watched files and directories. watcher.on('change', function (entries) { onWatcherChange(watcher, entries); }); return (_rxjsBundlesRxUmdMinJs2 || _rxjsBundlesRxUmdMinJs()).Observable.create(function (observer) { // Notify success watcher setup. observer.next('SUCCESS'); return function () { return unwatchDirectoryRecursive(directoryPath); }; }); }).publish(); } function onWatcherChange(subscription, entries) { var directoryChanges = new Set(); entries.forEach(function (entry) { var entryPath = (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.join(subscription.root, entry.name); var observer = entityObserver.get(entryPath); if (observer != null) { // TODO(most): handle `rename`, if needed. if (!entry.exists) { observer.next('delete'); observer.complete(); } else { observer.next('change'); } } // A file watch event can also be considered a directory change // for the parent directory if a file was created or deleted. if (entry.new || !entry.exists) { directoryChanges.add((_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.dirname(entryPath)); } }); directoryChanges.forEach(function (watchedDirectoryPath) { var observer = entityObserver.get(watchedDirectoryPath); if (observer != null) { observer.next('change'); } }); }