pax_global_header00006660000000000000000000000064142461175120014515gustar00rootroot0000000000000052 comment=dc690bbaea140820f1d9c7c2ec4dff8902798ff9 watchpack-2.4.0/000077500000000000000000000000001424611751200134655ustar00rootroot00000000000000watchpack-2.4.0/.editorconfig000066400000000000000000000004331424611751200161420ustar00rootroot00000000000000root = true [*] indent_style = tab indent_size = 2 charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true max_line_length = 80 [*.json] indent_style = space indent_size = 2 [*.yml] indent_style = space indent_size = 2 [*.md] trim_trailing_whitespace = false watchpack-2.4.0/.eslintrc.js000066400000000000000000000003531424611751200157250ustar00rootroot00000000000000module.exports = { env: { node: true, es6: true }, extends: ["plugin:prettier/recommended"], parserOptions: { ecmaVersion: 2018 }, plugins: ["prettier"], rules: { strict: 0, curly: 0, "no-underscore-dangle": 0 } }; watchpack-2.4.0/.gitattributes000066400000000000000000000000521424611751200163550ustar00rootroot00000000000000* text=auto examples/* eol=lf bin/* eol=lfwatchpack-2.4.0/.github/000077500000000000000000000000001424611751200150255ustar00rootroot00000000000000watchpack-2.4.0/.github/FUNDING.yml000066400000000000000000000000311424611751200166340ustar00rootroot00000000000000open_collective: webpack watchpack-2.4.0/.github/workflows/000077500000000000000000000000001424611751200170625ustar00rootroot00000000000000watchpack-2.4.0/.github/workflows/test.yml000066400000000000000000000043311424611751200205650ustar00rootroot00000000000000name: Test on: push: branches: - main pull_request: branches: - main jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Use Node.js uses: actions/setup-node@v1 with: node-version: 16.x - id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - uses: actions/cache@v1 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: ${{ runner.os }}-yarn- - run: yarn --frozen-lockfile - uses: actions/cache@v1 with: path: .eslintcache key: lint-${{ env.GITHUB_SHA }} restore-keys: lint- - run: yarn lint test: strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] node-version: [10.x, 12.x, 14.x, 16.x, 17.x] polling: ["false", "200"] exclude: - os: macos-latest node-version: 10.x polling: "200" - os: macos-latest node-version: 12.x polling: "200" - os: macos-latest node-version: 14.x polling: "200" - os: macos-latest node-version: 16.x polling: "200" - os: macos-latest node-version: 17.x polling: "200" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - uses: actions/cache@v1 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: ${{ runner.os }}-yarn- - run: yarn --frozen-lockfile - run: yarn cover --report lcovonly env: WATCHPACK_POLLING: ${{ matrix.polling }} - uses: codecov/codecov-action@v1 with: flags: integration functionalities: gcov watchpack-2.4.0/.gitignore000066400000000000000000000001261424611751200154540ustar00rootroot00000000000000/node_modules /test/fixtures /playground/folder /coverage .DS_Store package-lock.json watchpack-2.4.0/.prettierrc.js000066400000000000000000000002361424611751200162650ustar00rootroot00000000000000module.exports = { printWidth: 80, useTabs: true, tabWidth: 2, overrides: [ { files: "*.{json,yml}", options: { useTabs: false } } ] }; watchpack-2.4.0/.travis.yml000066400000000000000000000017371424611751200156060ustar00rootroot00000000000000sudo: false dist: trusty language: node_js stages: - basic - advanced matrix: include: - os: linux node_js: "14" stage: basic - os: osx node_js: "14" env: WATCHPACK_RECURSIVE_WATCHER_LOGGING=1 stage: basic - os: osx node_js: "14" env: WATCHPACK_WATCHER_LIMIT=1 stage: advanced - os: linux node_js: "14" env: WATCHPACK_POLLING=200 stage: advanced - os: linux node_js: "12" stage: advanced - os: linux node_js: "12" env: WATCHPACK_POLLING=200 stage: advanced - os: linux node_js: "10" stage: advanced - os: linux node_js: "10" env: WATCHPACK_POLLING=200 stage: advanced - os: osx node_js: "10" stage: advanced script: - yarn cover --report lcovonly after_success: - cat ./coverage/lcov.info | node_modules/.bin/coveralls --verbose - bash <(curl -s https://codecov.io/bash) -X gcov - rm -rf ./coverage watchpack-2.4.0/LICENSE000066400000000000000000000020571424611751200144760ustar00rootroot00000000000000Copyright JS Foundation and other contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. watchpack-2.4.0/README.md000066400000000000000000000154751424611751200147600ustar00rootroot00000000000000# watchpack Wrapper library for directory and file watching. [![Build Status][build-status]][build-status-url] [![Build status][build-status-veyor]][build-status-veyor-url] [![Test coverage][coveralls-image]][coveralls-url] [![codecov][codecov]][codecov-url] [![downloads][downloads]][downloads-url] [![Github contributors][contributors]][contributors-url] ## Concept watchpack high level API doesn't map directly to watchers. Instead a three level architecture ensures that for each directory only a single watcher exists. - The high level API requests `DirectoryWatchers` from a `WatcherManager`, which ensures that only a single `DirectoryWatcher` per directory is created. - A user-faced `Watcher` can be obtained from a `DirectoryWatcher` and provides a filtered view on the `DirectoryWatcher`. - Reference-counting is used on the `DirectoryWatcher` and `Watcher` to decide when to close them. - The real watchers are created by the `DirectoryWatcher`. - Files are never watched directly. This should keep the watcher count low. - Watching can be started in the past. This way watching can start after file reading. - Symlinks are not followed, instead the symlink is watched. ## API ```javascript var Watchpack = require("watchpack"); var wp = new Watchpack({ // options: aggregateTimeout: 1000, // fire "aggregated" event when after a change for 1000ms no additional change occurred // aggregated defaults to undefined, which doesn't fire an "aggregated" event poll: true, // poll: true - use polling with the default interval // poll: 10000 - use polling with an interval of 10s // poll defaults to undefined, which prefer native watching methods // Note: enable polling when watching on a network path // When WATCHPACK_POLLING environment variable is set it will override this option followSymlinks: true, // true: follows symlinks and watches symlinks and real files // (This makes sense when symlinks has not been resolved yet, comes with a performance hit) // false (default): watches only specified item they may be real files or symlinks // (This makes sense when symlinks has already been resolved) ignored: "**/.git" // ignored: "string" - a glob pattern for files or folders that should not be watched // ignored: ["string", "string"] - multiple glob patterns that should be ignored // ignored: /regexp/ - a regular expression for files or folders that should not be watched // ignored: (entry) => boolean - an arbitrary function which must return truthy to ignore an entry // For all cases expect the arbitrary function the path will have path separator normalized to '/'. // All subdirectories are ignored too }); // Watchpack.prototype.watch({ // files: Iterable, // directories: Iterable, // missing: Iterable, // startTime?: number // }) wp.watch({ files: listOfFiles, directories: listOfDirectories, missing: listOfNotExistingItems, startTime: Date.now() - 10000 }); // starts watching these files and directories // calling this again will override the files and directories // files: can be files or directories, for files: content and existence changes are tracked // for directories: only existence and timestamp changes are tracked // directories: only directories, directory content (and content of children, ...) and // existence changes are tracked. // assumed to exist, when directory is not found without further information a remove event is emitted // missing: can be files or directorees, // only existence changes are tracked // expected to not exist, no remove event is emitted when not found initially // files and directories are assumed to exist, when they are not found without further information a remove event is emitted // missing is assumed to not exist and no remove event is emitted wp.on("change", function(filePath, mtime, explanation) { // filePath: the changed file // mtime: last modified time for the changed file // explanation: textual information how this change was detected }); wp.on("remove", function(filePath, explanation) { // filePath: the removed file or directory // explanation: textual information how this change was detected }); wp.on("aggregated", function(changes, removals) { // changes: a Set of all changed files // removals: a Set of all removed files // watchpack gives up ownership on these Sets. }); // Watchpack.prototype.pause() wp.pause(); // stops emitting events, but keeps watchers open // next "watch" call can reuse the watchers // The watcher will keep aggregating events // which can be received with getAggregated() // Watchpack.prototype.close() wp.close(); // stops emitting events and closes all watchers // Watchpack.prototype.getAggregated(): { changes: Set, removals: Set } const { changes, removals } = wp.getAggregated(); // returns the current aggregated info and removes that from the watcher // The next aggregated event won't include that info and will only emitted // when futher changes happen // Can also be used when paused. // Watchpack.prototype.collectTimeInfoEntries(fileInfoEntries: Map, directoryInfoEntries: Map) wp.collectTimeInfoEntries(fileInfoEntries, directoryInfoEntries); // collects time info objects for all known files and directories // this include info from files not directly watched // key: absolute path, value: object with { safeTime, timestamp } // safeTime: a point in time at which it is safe to say all changes happened before that // timestamp: only for files, the mtime timestamp of the file // Watchpack.prototype.getTimeInfoEntries() var fileTimes = wp.getTimeInfoEntries(); // returns a Map with all known time info objects for files and directories // similar to collectTimeInfoEntries but returns a single map with all entries // (deprecated) // Watchpack.prototype.getTimes() var fileTimes = wp.getTimes(); // returns an object with all known change times for files // this include timestamps from files not directly watched // key: absolute path, value: timestamp as number ``` [build-status]: https://travis-ci.org/webpack/watchpack.svg?branch=main [build-status-url]: https://travis-ci.org/webpack/watchpack [build-status-veyor]: https://ci.appveyor.com/api/projects/status/e5u2qvmugtv0r647/branch/main?svg=true [build-status-veyor-url]: https://ci.appveyor.com/project/sokra/watchpack/branch/main [coveralls-url]: https://coveralls.io/r/webpack/watchpack/ [coveralls-image]: https://img.shields.io/coveralls/webpack/watchpack.svg [codecov]: https://codecov.io/gh/webpack/watchpack/branch/main/graph/badge.svg [codecov-url]: https://codecov.io/gh/webpack/watchpack [downloads]: https://img.shields.io/npm/dm/watchpack.svg [downloads-url]: https://www.npmjs.com/package/watchpack [contributors]: https://img.shields.io/github/contributors/webpack/watchpack.svg [contributors-url]: https://github.com/webpack/watchpack/graphs/contributors watchpack-2.4.0/appveyor.yml000066400000000000000000000007201424611751200160540ustar00rootroot00000000000000# appveyor file # http://www.appveyor.com/docs/appveyor-yml init: - git config --global core.autocrlf input cache: - "..\\.yarn-cache" # what combinations to test environment: matrix: - nodejs_version: 14 - nodejs_version: 12 - nodejs_version: 10 install: - ps: Install-Product node $env:nodejs_version x64 - yarn --preferred-cache-folder ..\\.yarn-cache build: off test_script: - node --version - yarn --version - cmd: yarn test watchpack-2.4.0/azure-pipelines-polling.yml000066400000000000000000000041061424611751200207670ustar00rootroot00000000000000jobs: - job: Linux pool: vmImage: ubuntu-latest strategy: maxParallel: 3 matrix: node-15: node_version: ^15.0.0 node-14: node_version: ^14.15.0 node-12: node_version: ^12.4.0 node-10: node_version: ^10.10.0 steps: - task: NodeTool@0 inputs: versionSpec: $(node_version) displayName: "Install Node.js $(node_version)" - script: | curl -o- -L https://yarnpkg.com/install.sh | bash displayName: "Install Yarn" - script: | set -e export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH" node -v yarn -v displayName: "Print versions" - script: | set -e export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH" yarn displayName: "Install dependencies" - script: | set -e export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH" yarn cover --report lcovonly env: WATCHPACK_POLLING: 200 displayName: "Run tests with coverage" - job: Windows pool: vmImage: windows-latest strategy: maxParallel: 3 matrix: node-15: node_version: ^15.0.0 node-14: node_version: ^14.15.0 node-12: node_version: ^12.4.0 node-10: node_version: ^10.10.0 steps: - task: NodeTool@0 inputs: versionSpec: $(node_version) displayName: "Install Node.js $(node_version)" - script: | npm install --global yarn displayName: "Install Yarn" - script: | set -e node -v yarn -v displayName: "Print versions" - script: | set -e yarn displayName: "Install dependencies" - script: | set -e yarn cover --report lcovonly env: WATCHPACK_POLLING: 200 displayName: "Run tests with coverage" watchpack-2.4.0/azure-pipelines.yml000066400000000000000000000062441424611751200173320ustar00rootroot00000000000000jobs: - job: Linux pool: vmImage: ubuntu-latest strategy: maxParallel: 3 matrix: node-15: node_version: ^15.0.0 node-14: node_version: ^14.15.0 node-12: node_version: ^12.4.0 node-10: node_version: ^10.13.0 steps: - task: NodeTool@0 inputs: versionSpec: $(node_version) displayName: "Install Node.js $(node_version)" - script: | curl -o- -L https://yarnpkg.com/install.sh | bash displayName: "Install Yarn" - script: | set -e export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH" node -v yarn -v displayName: "Print versions" - script: | set -e export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH" yarn displayName: "Install dependencies" - script: | set -e export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH" yarn cover --report lcovonly displayName: "Run tests with coverage" - job: macOS pool: vmImage: macOS-latest strategy: maxParallel: 3 matrix: node-15: node_version: ^15.0.0 node-14: node_version: ^14.15.0 node-12: node_version: ^12.4.0 node-10: node_version: ^10.13.0 steps: - task: NodeTool@0 inputs: versionSpec: $(node_version) displayName: "Install Node.js $(node_version)" - script: | curl -o- -L https://yarnpkg.com/install.sh | bash displayName: "Install Yarn" - script: | set -e export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH" node -v yarn -v displayName: "Print versions" - script: | set -e export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH" yarn displayName: "Install dependencies" - script: | set -e export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH" export WATCHPACK_RECURSIVE_WATCHER_LOGGING=1 yarn cover --report lcovonly displayName: "Run tests with coverage" - job: Windows pool: vmImage: windows-latest strategy: maxParallel: 3 matrix: node-15: node_version: ^15.0.0 node-14: node_version: ^14.15.0 node-12: node_version: ^12.4.0 node-10: node_version: ^10.13.0 steps: - task: NodeTool@0 inputs: versionSpec: $(node_version) displayName: "Install Node.js $(node_version)" - script: | npm install --global yarn displayName: "Install Yarn" - script: | set -e node -v yarn -v displayName: "Print versions" - script: | set -e yarn displayName: "Install dependencies" - script: | set -e yarn cover --report lcovonly displayName: "Run tests with coverage" watchpack-2.4.0/lib/000077500000000000000000000000001424611751200142335ustar00rootroot00000000000000watchpack-2.4.0/lib/DirectoryWatcher.js000066400000000000000000000500731424611751200200600ustar00rootroot00000000000000/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const EventEmitter = require("events").EventEmitter; const fs = require("graceful-fs"); const path = require("path"); const watchEventSource = require("./watchEventSource"); const EXISTANCE_ONLY_TIME_ENTRY = Object.freeze({}); let FS_ACCURACY = 2000; const IS_OSX = require("os").platform() === "darwin"; const WATCHPACK_POLLING = process.env.WATCHPACK_POLLING; const FORCE_POLLING = `${+WATCHPACK_POLLING}` === WATCHPACK_POLLING ? +WATCHPACK_POLLING : !!WATCHPACK_POLLING && WATCHPACK_POLLING !== "false"; function withoutCase(str) { return str.toLowerCase(); } function needCalls(times, callback) { return function() { if (--times === 0) { return callback(); } }; } class Watcher extends EventEmitter { constructor(directoryWatcher, filePath, startTime) { super(); this.directoryWatcher = directoryWatcher; this.path = filePath; this.startTime = startTime && +startTime; } checkStartTime(mtime, initial) { const startTime = this.startTime; if (typeof startTime !== "number") return !initial; return startTime <= mtime; } close() { this.emit("closed"); } } class DirectoryWatcher extends EventEmitter { constructor(watcherManager, directoryPath, options) { super(); if (FORCE_POLLING) { options.poll = FORCE_POLLING; } this.watcherManager = watcherManager; this.options = options; this.path = directoryPath; // safeTime is the point in time after which reading is safe to be unchanged // timestamp is a value that should be compared with another timestamp (mtime) /** @type {Map} */ this.filesWithoutCase = new Map(); this.directories = new Map(); this.lastWatchEvent = 0; this.initialScan = true; this.ignored = options.ignored || (() => false); this.nestedWatching = false; this.polledWatching = typeof options.poll === "number" ? options.poll : options.poll ? 5007 : false; this.timeout = undefined; this.initialScanRemoved = new Set(); this.initialScanFinished = undefined; /** @type {Map>} */ this.watchers = new Map(); this.parentWatcher = null; this.refs = 0; this._activeEvents = new Map(); this.closed = false; this.scanning = false; this.scanAgain = false; this.scanAgainInitial = false; this.createWatcher(); this.doScan(true); } createWatcher() { try { if (this.polledWatching) { this.watcher = { close: () => { if (this.timeout) { clearTimeout(this.timeout); this.timeout = undefined; } } }; } else { if (IS_OSX) { this.watchInParentDirectory(); } this.watcher = watchEventSource.watch(this.path); this.watcher.on("change", this.onWatchEvent.bind(this)); this.watcher.on("error", this.onWatcherError.bind(this)); } } catch (err) { this.onWatcherError(err); } } forEachWatcher(path, fn) { const watchers = this.watchers.get(withoutCase(path)); if (watchers !== undefined) { for (const w of watchers) { fn(w); } } } setMissing(itemPath, initial, type) { if (this.initialScan) { this.initialScanRemoved.add(itemPath); } const oldDirectory = this.directories.get(itemPath); if (oldDirectory) { if (this.nestedWatching) oldDirectory.close(); this.directories.delete(itemPath); this.forEachWatcher(itemPath, w => w.emit("remove", type)); if (!initial) { this.forEachWatcher(this.path, w => w.emit("change", itemPath, null, type, initial) ); } } const oldFile = this.files.get(itemPath); if (oldFile) { this.files.delete(itemPath); const key = withoutCase(itemPath); const count = this.filesWithoutCase.get(key) - 1; if (count <= 0) { this.filesWithoutCase.delete(key); this.forEachWatcher(itemPath, w => w.emit("remove", type)); } else { this.filesWithoutCase.set(key, count); } if (!initial) { this.forEachWatcher(this.path, w => w.emit("change", itemPath, null, type, initial) ); } } } setFileTime(filePath, mtime, initial, ignoreWhenEqual, type) { const now = Date.now(); if (this.ignored(filePath)) return; const old = this.files.get(filePath); let safeTime, accuracy; if (initial) { safeTime = Math.min(now, mtime) + FS_ACCURACY; accuracy = FS_ACCURACY; } else { safeTime = now; accuracy = 0; if (old && old.timestamp === mtime && mtime + FS_ACCURACY < now) { // We are sure that mtime is untouched // This can be caused by some file attribute change // e. g. when access time has been changed // but the file content is untouched return; } } if (ignoreWhenEqual && old && old.timestamp === mtime) return; this.files.set(filePath, { safeTime, accuracy, timestamp: mtime }); if (!old) { const key = withoutCase(filePath); const count = this.filesWithoutCase.get(key); this.filesWithoutCase.set(key, (count || 0) + 1); if (count !== undefined) { // There is already a file with case-insensitive-equal name // On a case-insensitive filesystem we may miss the renaming // when only casing is changed. // To be sure that our information is correct // we trigger a rescan here this.doScan(false); } this.forEachWatcher(filePath, w => { if (!initial || w.checkStartTime(safeTime, initial)) { w.emit("change", mtime, type); } }); } else if (!initial) { this.forEachWatcher(filePath, w => w.emit("change", mtime, type)); } this.forEachWatcher(this.path, w => { if (!initial || w.checkStartTime(safeTime, initial)) { w.emit("change", filePath, safeTime, type, initial); } }); } setDirectory(directoryPath, birthtime, initial, type) { if (this.ignored(directoryPath)) return; if (directoryPath === this.path) { if (!initial) { this.forEachWatcher(this.path, w => w.emit("change", directoryPath, birthtime, type, initial) ); } } else { const old = this.directories.get(directoryPath); if (!old) { const now = Date.now(); if (this.nestedWatching) { this.createNestedWatcher(directoryPath); } else { this.directories.set(directoryPath, true); } let safeTime; if (initial) { safeTime = Math.min(now, birthtime) + FS_ACCURACY; } else { safeTime = now; } this.forEachWatcher(directoryPath, w => { if (!initial || w.checkStartTime(safeTime, false)) { w.emit("change", birthtime, type); } }); this.forEachWatcher(this.path, w => { if (!initial || w.checkStartTime(safeTime, initial)) { w.emit("change", directoryPath, safeTime, type, initial); } }); } } } createNestedWatcher(directoryPath) { const watcher = this.watcherManager.watchDirectory(directoryPath, 1); watcher.on("change", (filePath, mtime, type, initial) => { this.forEachWatcher(this.path, w => { if (!initial || w.checkStartTime(mtime, initial)) { w.emit("change", filePath, mtime, type, initial); } }); }); this.directories.set(directoryPath, watcher); } setNestedWatching(flag) { if (this.nestedWatching !== !!flag) { this.nestedWatching = !!flag; if (this.nestedWatching) { for (const directory of this.directories.keys()) { this.createNestedWatcher(directory); } } else { for (const [directory, watcher] of this.directories) { watcher.close(); this.directories.set(directory, true); } } } } watch(filePath, startTime) { const key = withoutCase(filePath); let watchers = this.watchers.get(key); if (watchers === undefined) { watchers = new Set(); this.watchers.set(key, watchers); } this.refs++; const watcher = new Watcher(this, filePath, startTime); watcher.on("closed", () => { if (--this.refs <= 0) { this.close(); return; } watchers.delete(watcher); if (watchers.size === 0) { this.watchers.delete(key); if (this.path === filePath) this.setNestedWatching(false); } }); watchers.add(watcher); let safeTime; if (filePath === this.path) { this.setNestedWatching(true); safeTime = this.lastWatchEvent; for (const entry of this.files.values()) { fixupEntryAccuracy(entry); safeTime = Math.max(safeTime, entry.safeTime); } } else { const entry = this.files.get(filePath); if (entry) { fixupEntryAccuracy(entry); safeTime = entry.safeTime; } else { safeTime = 0; } } if (safeTime) { if (safeTime >= startTime) { process.nextTick(() => { if (this.closed) return; if (filePath === this.path) { watcher.emit( "change", filePath, safeTime, "watch (outdated on attach)", true ); } else { watcher.emit( "change", safeTime, "watch (outdated on attach)", true ); } }); } } else if (this.initialScan) { if (this.initialScanRemoved.has(filePath)) { process.nextTick(() => { if (this.closed) return; watcher.emit("remove"); }); } } else if ( !this.directories.has(filePath) && watcher.checkStartTime(this.initialScanFinished, false) ) { process.nextTick(() => { if (this.closed) return; watcher.emit("initial-missing", "watch (missing on attach)"); }); } return watcher; } onWatchEvent(eventType, filename) { if (this.closed) return; if (!filename) { // In some cases no filename is provided // This seem to happen on windows // So some event happened but we don't know which file is affected // We have to do a full scan of the directory this.doScan(false); return; } const filePath = path.join(this.path, filename); if (this.ignored(filePath)) return; if (this._activeEvents.get(filename) === undefined) { this._activeEvents.set(filename, false); const checkStats = () => { if (this.closed) return; this._activeEvents.set(filename, false); fs.lstat(filePath, (err, stats) => { if (this.closed) return; if (this._activeEvents.get(filename) === true) { process.nextTick(checkStats); return; } this._activeEvents.delete(filename); // ENOENT happens when the file/directory doesn't exist // EPERM happens when the containing directory doesn't exist if (err) { if ( err.code !== "ENOENT" && err.code !== "EPERM" && err.code !== "EBUSY" ) { this.onStatsError(err); } else { if (filename === path.basename(this.path)) { // This may indicate that the directory itself was removed if (!fs.existsSync(this.path)) { this.onDirectoryRemoved("stat failed"); } } } } this.lastWatchEvent = Date.now(); if (!stats) { this.setMissing(filePath, false, eventType); } else if (stats.isDirectory()) { this.setDirectory( filePath, +stats.birthtime || 1, false, eventType ); } else if (stats.isFile() || stats.isSymbolicLink()) { if (stats.mtime) { ensureFsAccuracy(stats.mtime); } this.setFileTime( filePath, +stats.mtime || +stats.ctime || 1, false, false, eventType ); } }); }; process.nextTick(checkStats); } else { this._activeEvents.set(filename, true); } } onWatcherError(err) { if (this.closed) return; if (err) { if (err.code !== "EPERM" && err.code !== "ENOENT") { console.error("Watchpack Error (watcher): " + err); } this.onDirectoryRemoved("watch error"); } } onStatsError(err) { if (err) { console.error("Watchpack Error (stats): " + err); } } onScanError(err) { if (err) { console.error("Watchpack Error (initial scan): " + err); } this.onScanFinished(); } onScanFinished() { if (this.polledWatching) { this.timeout = setTimeout(() => { if (this.closed) return; this.doScan(false); }, this.polledWatching); } } onDirectoryRemoved(reason) { if (this.watcher) { this.watcher.close(); this.watcher = null; } this.watchInParentDirectory(); const type = `directory-removed (${reason})`; for (const directory of this.directories.keys()) { this.setMissing(directory, null, type); } for (const file of this.files.keys()) { this.setMissing(file, null, type); } } watchInParentDirectory() { if (!this.parentWatcher) { const parentDir = path.dirname(this.path); // avoid watching in the root directory // removing directories in the root directory is not supported if (path.dirname(parentDir) === parentDir) return; this.parentWatcher = this.watcherManager.watchFile(this.path, 1); this.parentWatcher.on("change", (mtime, type) => { if (this.closed) return; // On non-osx platforms we don't need this watcher to detect // directory removal, as an EPERM error indicates that if ((!IS_OSX || this.polledWatching) && this.parentWatcher) { this.parentWatcher.close(); this.parentWatcher = null; } // Try to create the watcher when parent directory is found if (!this.watcher) { this.createWatcher(); this.doScan(false); // directory was created so we emit an event this.forEachWatcher(this.path, w => w.emit("change", this.path, mtime, type, false) ); } }); this.parentWatcher.on("remove", () => { this.onDirectoryRemoved("parent directory removed"); }); } } doScan(initial) { if (this.scanning) { if (this.scanAgain) { if (!initial) this.scanAgainInitial = false; } else { this.scanAgain = true; this.scanAgainInitial = initial; } return; } this.scanning = true; if (this.timeout) { clearTimeout(this.timeout); this.timeout = undefined; } process.nextTick(() => { if (this.closed) return; fs.readdir(this.path, (err, items) => { if (this.closed) return; if (err) { if (err.code === "ENOENT" || err.code === "EPERM") { this.onDirectoryRemoved("scan readdir failed"); } else { this.onScanError(err); } this.initialScan = false; this.initialScanFinished = Date.now(); if (initial) { for (const watchers of this.watchers.values()) { for (const watcher of watchers) { if (watcher.checkStartTime(this.initialScanFinished, false)) { watcher.emit( "initial-missing", "scan (parent directory missing in initial scan)" ); } } } } if (this.scanAgain) { this.scanAgain = false; this.doScan(this.scanAgainInitial); } else { this.scanning = false; } return; } const itemPaths = new Set( items.map(item => path.join(this.path, item.normalize("NFC"))) ); for (const file of this.files.keys()) { if (!itemPaths.has(file)) { this.setMissing(file, initial, "scan (missing)"); } } for (const directory of this.directories.keys()) { if (!itemPaths.has(directory)) { this.setMissing(directory, initial, "scan (missing)"); } } if (this.scanAgain) { // Early repeat of scan this.scanAgain = false; this.doScan(initial); return; } const itemFinished = needCalls(itemPaths.size + 1, () => { if (this.closed) return; this.initialScan = false; this.initialScanRemoved = null; this.initialScanFinished = Date.now(); if (initial) { const missingWatchers = new Map(this.watchers); missingWatchers.delete(withoutCase(this.path)); for (const item of itemPaths) { missingWatchers.delete(withoutCase(item)); } for (const watchers of missingWatchers.values()) { for (const watcher of watchers) { if (watcher.checkStartTime(this.initialScanFinished, false)) { watcher.emit( "initial-missing", "scan (missing in initial scan)" ); } } } } if (this.scanAgain) { this.scanAgain = false; this.doScan(this.scanAgainInitial); } else { this.scanning = false; this.onScanFinished(); } }); for (const itemPath of itemPaths) { fs.lstat(itemPath, (err2, stats) => { if (this.closed) return; if (err2) { if ( err2.code === "ENOENT" || err2.code === "EPERM" || err2.code === "EACCES" || err2.code === "EBUSY" ) { this.setMissing(itemPath, initial, "scan (" + err2.code + ")"); } else { this.onScanError(err2); } itemFinished(); return; } if (stats.isFile() || stats.isSymbolicLink()) { if (stats.mtime) { ensureFsAccuracy(stats.mtime); } this.setFileTime( itemPath, +stats.mtime || +stats.ctime || 1, initial, true, "scan (file)" ); } else if (stats.isDirectory()) { if (!initial || !this.directories.has(itemPath)) this.setDirectory( itemPath, +stats.birthtime || 1, initial, "scan (dir)" ); } itemFinished(); }); } itemFinished(); }); }); } getTimes() { const obj = Object.create(null); let safeTime = this.lastWatchEvent; for (const [file, entry] of this.files) { fixupEntryAccuracy(entry); safeTime = Math.max(safeTime, entry.safeTime); obj[file] = Math.max(entry.safeTime, entry.timestamp); } if (this.nestedWatching) { for (const w of this.directories.values()) { const times = w.directoryWatcher.getTimes(); for (const file of Object.keys(times)) { const time = times[file]; safeTime = Math.max(safeTime, time); obj[file] = time; } } obj[this.path] = safeTime; } if (!this.initialScan) { for (const watchers of this.watchers.values()) { for (const watcher of watchers) { const path = watcher.path; if (!Object.prototype.hasOwnProperty.call(obj, path)) { obj[path] = null; } } } } return obj; } collectTimeInfoEntries(fileTimestamps, directoryTimestamps) { let safeTime = this.lastWatchEvent; for (const [file, entry] of this.files) { fixupEntryAccuracy(entry); safeTime = Math.max(safeTime, entry.safeTime); fileTimestamps.set(file, entry); } if (this.nestedWatching) { for (const w of this.directories.values()) { safeTime = Math.max( safeTime, w.directoryWatcher.collectTimeInfoEntries( fileTimestamps, directoryTimestamps ) ); } fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY); directoryTimestamps.set(this.path, { safeTime }); } else { for (const dir of this.directories.keys()) { // No additional info about this directory // but maybe another DirectoryWatcher has info fileTimestamps.set(dir, EXISTANCE_ONLY_TIME_ENTRY); if (!directoryTimestamps.has(dir)) directoryTimestamps.set(dir, EXISTANCE_ONLY_TIME_ENTRY); } fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY); directoryTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY); } if (!this.initialScan) { for (const watchers of this.watchers.values()) { for (const watcher of watchers) { const path = watcher.path; if (!fileTimestamps.has(path)) { fileTimestamps.set(path, null); } } } } return safeTime; } close() { this.closed = true; this.initialScan = false; if (this.watcher) { this.watcher.close(); this.watcher = null; } if (this.nestedWatching) { for (const w of this.directories.values()) { w.close(); } this.directories.clear(); } if (this.parentWatcher) { this.parentWatcher.close(); this.parentWatcher = null; } this.emit("closed"); } } module.exports = DirectoryWatcher; module.exports.EXISTANCE_ONLY_TIME_ENTRY = EXISTANCE_ONLY_TIME_ENTRY; function fixupEntryAccuracy(entry) { if (entry.accuracy > FS_ACCURACY) { entry.safeTime = entry.safeTime - entry.accuracy + FS_ACCURACY; entry.accuracy = FS_ACCURACY; } } function ensureFsAccuracy(mtime) { if (!mtime) return; if (FS_ACCURACY > 1 && mtime % 1 !== 0) FS_ACCURACY = 1; else if (FS_ACCURACY > 10 && mtime % 10 !== 0) FS_ACCURACY = 10; else if (FS_ACCURACY > 100 && mtime % 100 !== 0) FS_ACCURACY = 100; else if (FS_ACCURACY > 1000 && mtime % 1000 !== 0) FS_ACCURACY = 1000; } watchpack-2.4.0/lib/LinkResolver.js000066400000000000000000000062171424611751200172160ustar00rootroot00000000000000/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const fs = require("fs"); const path = require("path"); // macOS, Linux, and Windows all rely on these errors const EXPECTED_ERRORS = new Set(["EINVAL", "ENOENT"]); // On Windows there is also this error in some cases if (process.platform === "win32") EXPECTED_ERRORS.add("UNKNOWN"); class LinkResolver { constructor() { this.cache = new Map(); } /** * @param {string} file path to file or directory * @returns {string[]} array of file and all symlinks contributed in the resolving process (first item is the resolved file) */ resolve(file) { const cacheEntry = this.cache.get(file); if (cacheEntry !== undefined) { return cacheEntry; } const parent = path.dirname(file); if (parent === file) { // At root of filesystem there can't be a link const result = Object.freeze([file]); this.cache.set(file, result); return result; } // resolve the parent directory to find links there and get the real path const parentResolved = this.resolve(parent); let realFile = file; // is the parent directory really somewhere else? if (parentResolved[0] !== parent) { // get the real location of file const basename = path.basename(file); realFile = path.resolve(parentResolved[0], basename); } // try to read the link content try { const linkContent = fs.readlinkSync(realFile); // resolve the link content relative to the parent directory const resolvedLink = path.resolve(parentResolved[0], linkContent); // recursive resolve the link content for more links in the structure const linkResolved = this.resolve(resolvedLink); // merge parent and link resolve results let result; if (linkResolved.length > 1 && parentResolved.length > 1) { // when both contain links we need to duplicate them with a Set const resultSet = new Set(linkResolved); // add the link resultSet.add(realFile); // add all symlinks of the parent for (let i = 1; i < parentResolved.length; i++) { resultSet.add(parentResolved[i]); } result = Object.freeze(Array.from(resultSet)); } else if (parentResolved.length > 1) { // we have links in the parent but not for the link content location result = parentResolved.slice(); result[0] = linkResolved[0]; // add the link result.push(realFile); Object.freeze(result); } else if (linkResolved.length > 1) { // we can return the link content location result result = linkResolved.slice(); // add the link result.push(realFile); Object.freeze(result); } else { // neither link content location nor parent have links // this link is the only link here result = Object.freeze([ // the resolve real location linkResolved[0], // add the link realFile ]); } this.cache.set(file, result); return result; } catch (e) { if (!EXPECTED_ERRORS.has(e.code)) { throw e; } // no link const result = parentResolved.slice(); result[0] = realFile; Object.freeze(result); this.cache.set(file, result); return result; } } } module.exports = LinkResolver; watchpack-2.4.0/lib/getWatcherManager.js000066400000000000000000000026531424611751200201670ustar00rootroot00000000000000/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const path = require("path"); const DirectoryWatcher = require("./DirectoryWatcher"); class WatcherManager { constructor(options) { this.options = options; this.directoryWatchers = new Map(); } getDirectoryWatcher(directory) { const watcher = this.directoryWatchers.get(directory); if (watcher === undefined) { const newWatcher = new DirectoryWatcher(this, directory, this.options); this.directoryWatchers.set(directory, newWatcher); newWatcher.on("closed", () => { this.directoryWatchers.delete(directory); }); return newWatcher; } return watcher; } watchFile(p, startTime) { const directory = path.dirname(p); if (directory === p) return null; return this.getDirectoryWatcher(directory).watch(p, startTime); } watchDirectory(directory, startTime) { return this.getDirectoryWatcher(directory).watch(directory, startTime); } } const watcherManagers = new WeakMap(); /** * @param {object} options options * @returns {WatcherManager} the watcher manager */ module.exports = options => { const watcherManager = watcherManagers.get(options); if (watcherManager !== undefined) return watcherManager; const newWatcherManager = new WatcherManager(options); watcherManagers.set(options, newWatcherManager); return newWatcherManager; }; module.exports.WatcherManager = WatcherManager; watchpack-2.4.0/lib/reducePlan.js000066400000000000000000000070161424611751200166570ustar00rootroot00000000000000/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const path = require("path"); /** * @template T * @typedef {Object} TreeNode * @property {string} filePath * @property {TreeNode} parent * @property {TreeNode[]} children * @property {number} entries * @property {boolean} active * @property {T[] | T | undefined} value */ /** * @template T * @param {Map>} the new plan */ module.exports = (plan, limit) => { const treeMap = new Map(); // Convert to tree for (const [filePath, value] of plan) { treeMap.set(filePath, { filePath, parent: undefined, children: undefined, entries: 1, active: true, value }); } let currentCount = treeMap.size; // Create parents and calculate sum of entries for (const node of treeMap.values()) { const parentPath = path.dirname(node.filePath); if (parentPath !== node.filePath) { let parent = treeMap.get(parentPath); if (parent === undefined) { parent = { filePath: parentPath, parent: undefined, children: [node], entries: node.entries, active: false, value: undefined }; treeMap.set(parentPath, parent); node.parent = parent; } else { node.parent = parent; if (parent.children === undefined) { parent.children = [node]; } else { parent.children.push(node); } do { parent.entries += node.entries; parent = parent.parent; } while (parent); } } } // Reduce until limit reached while (currentCount > limit) { // Select node that helps reaching the limit most effectively without overmerging const overLimit = currentCount - limit; let bestNode = undefined; let bestCost = Infinity; for (const node of treeMap.values()) { if (node.entries <= 1 || !node.children || !node.parent) continue; if (node.children.length === 0) continue; if (node.children.length === 1 && !node.value) continue; // Try to select the node with has just a bit more entries than we need to reduce // When just a bit more is over 30% over the limit, // also consider just a bit less entries then we need to reduce const cost = node.entries - 1 >= overLimit ? node.entries - 1 - overLimit : overLimit - node.entries + 1 + limit * 0.3; if (cost < bestCost) { bestNode = node; bestCost = cost; } } if (!bestNode) break; // Merge all children const reduction = bestNode.entries - 1; bestNode.active = true; bestNode.entries = 1; currentCount -= reduction; let parent = bestNode.parent; while (parent) { parent.entries -= reduction; parent = parent.parent; } const queue = new Set(bestNode.children); for (const node of queue) { node.active = false; node.entries = 0; if (node.children) { for (const child of node.children) queue.add(child); } } } // Write down new plan const newPlan = new Map(); for (const rootNode of treeMap.values()) { if (!rootNode.active) continue; const map = new Map(); const queue = new Set([rootNode]); for (const node of queue) { if (node.active && node !== rootNode) continue; if (node.value) { if (Array.isArray(node.value)) { for (const item of node.value) { map.set(item, node.filePath); } } else { map.set(node.value, node.filePath); } } if (node.children) { for (const child of node.children) { queue.add(child); } } } newPlan.set(rootNode.filePath, map); } return newPlan; }; watchpack-2.4.0/lib/watchEventSource.js000066400000000000000000000205421424611751200200650ustar00rootroot00000000000000/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const fs = require("fs"); const path = require("path"); const { EventEmitter } = require("events"); const reducePlan = require("./reducePlan"); const IS_OSX = require("os").platform() === "darwin"; const IS_WIN = require("os").platform() === "win32"; const SUPPORTS_RECURSIVE_WATCHING = IS_OSX || IS_WIN; const watcherLimit = +process.env.WATCHPACK_WATCHER_LIMIT || (IS_OSX ? 2000 : 10000); const recursiveWatcherLogging = !!process.env .WATCHPACK_RECURSIVE_WATCHER_LOGGING; let isBatch = false; let watcherCount = 0; /** @type {Map} */ const pendingWatchers = new Map(); /** @type {Map} */ const recursiveWatchers = new Map(); /** @type {Map} */ const directWatchers = new Map(); /** @type {Map} */ const underlyingWatcher = new Map(); class DirectWatcher { constructor(filePath) { this.filePath = filePath; this.watchers = new Set(); this.watcher = undefined; try { const watcher = fs.watch(filePath); this.watcher = watcher; watcher.on("change", (type, filename) => { for (const w of this.watchers) { w.emit("change", type, filename); } }); watcher.on("error", error => { for (const w of this.watchers) { w.emit("error", error); } }); } catch (err) { process.nextTick(() => { for (const w of this.watchers) { w.emit("error", err); } }); } watcherCount++; } add(watcher) { underlyingWatcher.set(watcher, this); this.watchers.add(watcher); } remove(watcher) { this.watchers.delete(watcher); if (this.watchers.size === 0) { directWatchers.delete(this.filePath); watcherCount--; if (this.watcher) this.watcher.close(); } } getWatchers() { return this.watchers; } } class RecursiveWatcher { constructor(rootPath) { this.rootPath = rootPath; /** @type {Map} */ this.mapWatcherToPath = new Map(); /** @type {Map>} */ this.mapPathToWatchers = new Map(); this.watcher = undefined; try { const watcher = fs.watch(rootPath, { recursive: true }); this.watcher = watcher; watcher.on("change", (type, filename) => { if (!filename) { if (recursiveWatcherLogging) { process.stderr.write( `[watchpack] dispatch ${type} event in recursive watcher (${ this.rootPath }) to all watchers\n` ); } for (const w of this.mapWatcherToPath.keys()) { w.emit("change", type); } } else { const dir = path.dirname(filename); const watchers = this.mapPathToWatchers.get(dir); if (recursiveWatcherLogging) { process.stderr.write( `[watchpack] dispatch ${type} event in recursive watcher (${ this.rootPath }) for '${filename}' to ${ watchers ? watchers.size : 0 } watchers\n` ); } if (watchers === undefined) return; for (const w of watchers) { w.emit("change", type, path.basename(filename)); } } }); watcher.on("error", error => { for (const w of this.mapWatcherToPath.keys()) { w.emit("error", error); } }); } catch (err) { process.nextTick(() => { for (const w of this.mapWatcherToPath.keys()) { w.emit("error", err); } }); } watcherCount++; if (recursiveWatcherLogging) { process.stderr.write( `[watchpack] created recursive watcher at ${rootPath}\n` ); } } add(filePath, watcher) { underlyingWatcher.set(watcher, this); const subpath = filePath.slice(this.rootPath.length + 1) || "."; this.mapWatcherToPath.set(watcher, subpath); const set = this.mapPathToWatchers.get(subpath); if (set === undefined) { const newSet = new Set(); newSet.add(watcher); this.mapPathToWatchers.set(subpath, newSet); } else { set.add(watcher); } } remove(watcher) { const subpath = this.mapWatcherToPath.get(watcher); if (!subpath) return; this.mapWatcherToPath.delete(watcher); const set = this.mapPathToWatchers.get(subpath); set.delete(watcher); if (set.size === 0) { this.mapPathToWatchers.delete(subpath); } if (this.mapWatcherToPath.size === 0) { recursiveWatchers.delete(this.rootPath); watcherCount--; if (this.watcher) this.watcher.close(); if (recursiveWatcherLogging) { process.stderr.write( `[watchpack] closed recursive watcher at ${this.rootPath}\n` ); } } } getWatchers() { return this.mapWatcherToPath; } } class Watcher extends EventEmitter { close() { if (pendingWatchers.has(this)) { pendingWatchers.delete(this); return; } const watcher = underlyingWatcher.get(this); watcher.remove(this); underlyingWatcher.delete(this); } } const createDirectWatcher = filePath => { const existing = directWatchers.get(filePath); if (existing !== undefined) return existing; const w = new DirectWatcher(filePath); directWatchers.set(filePath, w); return w; }; const createRecursiveWatcher = rootPath => { const existing = recursiveWatchers.get(rootPath); if (existing !== undefined) return existing; const w = new RecursiveWatcher(rootPath); recursiveWatchers.set(rootPath, w); return w; }; const execute = () => { /** @type {Map} */ const map = new Map(); const addWatcher = (watcher, filePath) => { const entry = map.get(filePath); if (entry === undefined) { map.set(filePath, watcher); } else if (Array.isArray(entry)) { entry.push(watcher); } else { map.set(filePath, [entry, watcher]); } }; for (const [watcher, filePath] of pendingWatchers) { addWatcher(watcher, filePath); } pendingWatchers.clear(); // Fast case when we are not reaching the limit if (!SUPPORTS_RECURSIVE_WATCHING || watcherLimit - watcherCount >= map.size) { // Create watchers for all entries in the map for (const [filePath, entry] of map) { const w = createDirectWatcher(filePath); if (Array.isArray(entry)) { for (const item of entry) w.add(item); } else { w.add(entry); } } return; } // Reconsider existing watchers to improving watch plan for (const watcher of recursiveWatchers.values()) { for (const [w, subpath] of watcher.getWatchers()) { addWatcher(w, path.join(watcher.rootPath, subpath)); } } for (const watcher of directWatchers.values()) { for (const w of watcher.getWatchers()) { addWatcher(w, watcher.filePath); } } // Merge map entries to keep watcher limit // Create a 10% buffer to be able to enter fast case more often const plan = reducePlan(map, watcherLimit * 0.9); // Update watchers for all entries in the map for (const [filePath, entry] of plan) { if (entry.size === 1) { for (const [watcher, filePath] of entry) { const w = createDirectWatcher(filePath); const old = underlyingWatcher.get(watcher); if (old === w) continue; w.add(watcher); if (old !== undefined) old.remove(watcher); } } else { const filePaths = new Set(entry.values()); if (filePaths.size > 1) { const w = createRecursiveWatcher(filePath); for (const [watcher, watcherPath] of entry) { const old = underlyingWatcher.get(watcher); if (old === w) continue; w.add(watcherPath, watcher); if (old !== undefined) old.remove(watcher); } } else { for (const filePath of filePaths) { const w = createDirectWatcher(filePath); for (const watcher of entry.keys()) { const old = underlyingWatcher.get(watcher); if (old === w) continue; w.add(watcher); if (old !== undefined) old.remove(watcher); } } } } } }; exports.watch = filePath => { const watcher = new Watcher(); // Find an existing watcher const directWatcher = directWatchers.get(filePath); if (directWatcher !== undefined) { directWatcher.add(watcher); return watcher; } let current = filePath; for (;;) { const recursiveWatcher = recursiveWatchers.get(current); if (recursiveWatcher !== undefined) { recursiveWatcher.add(filePath, watcher); return watcher; } const parent = path.dirname(current); if (parent === current) break; current = parent; } // Queue up watcher for creation pendingWatchers.set(watcher, filePath); if (!isBatch) execute(); return watcher; }; exports.batch = fn => { isBatch = true; try { fn(); } finally { isBatch = false; execute(); } }; exports.getNumberOfWatchers = () => { return watcherCount; }; watchpack-2.4.0/lib/watchpack.js000066400000000000000000000242261424611751200165440ustar00rootroot00000000000000/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const getWatcherManager = require("./getWatcherManager"); const LinkResolver = require("./LinkResolver"); const EventEmitter = require("events").EventEmitter; const globToRegExp = require("glob-to-regexp"); const watchEventSource = require("./watchEventSource"); const EMPTY_ARRAY = []; const EMPTY_OPTIONS = {}; function addWatchersToSet(watchers, set) { for (const ww of watchers) { const w = ww.watcher; if (!set.has(w.directoryWatcher)) { set.add(w.directoryWatcher); } } } const stringToRegexp = ignored => { const source = globToRegExp(ignored, { globstar: true, extended: true }) .source; const matchingStart = source.slice(0, source.length - 1) + "(?:$|\\/)"; return matchingStart; }; const ignoredToFunction = ignored => { if (Array.isArray(ignored)) { const regexp = new RegExp(ignored.map(i => stringToRegexp(i)).join("|")); return x => regexp.test(x.replace(/\\/g, "/")); } else if (typeof ignored === "string") { const regexp = new RegExp(stringToRegexp(ignored)); return x => regexp.test(x.replace(/\\/g, "/")); } else if (ignored instanceof RegExp) { return x => ignored.test(x.replace(/\\/g, "/")); } else if (ignored instanceof Function) { return ignored; } else if (ignored) { throw new Error(`Invalid option for 'ignored': ${ignored}`); } else { return () => false; } }; const normalizeOptions = options => { return { followSymlinks: !!options.followSymlinks, ignored: ignoredToFunction(options.ignored), poll: options.poll }; }; const normalizeCache = new WeakMap(); const cachedNormalizeOptions = options => { const cacheEntry = normalizeCache.get(options); if (cacheEntry !== undefined) return cacheEntry; const normalized = normalizeOptions(options); normalizeCache.set(options, normalized); return normalized; }; class WatchpackFileWatcher { constructor(watchpack, watcher, files) { this.files = Array.isArray(files) ? files : [files]; this.watcher = watcher; watcher.on("initial-missing", type => { for (const file of this.files) { if (!watchpack._missing.has(file)) watchpack._onRemove(file, file, type); } }); watcher.on("change", (mtime, type) => { for (const file of this.files) { watchpack._onChange(file, mtime, file, type); } }); watcher.on("remove", type => { for (const file of this.files) { watchpack._onRemove(file, file, type); } }); } update(files) { if (!Array.isArray(files)) { if (this.files.length !== 1) { this.files = [files]; } else if (this.files[0] !== files) { this.files[0] = files; } } else { this.files = files; } } close() { this.watcher.close(); } } class WatchpackDirectoryWatcher { constructor(watchpack, watcher, directories) { this.directories = Array.isArray(directories) ? directories : [directories]; this.watcher = watcher; watcher.on("initial-missing", type => { for (const item of this.directories) { watchpack._onRemove(item, item, type); } }); watcher.on("change", (file, mtime, type) => { for (const item of this.directories) { watchpack._onChange(item, mtime, file, type); } }); watcher.on("remove", type => { for (const item of this.directories) { watchpack._onRemove(item, item, type); } }); } update(directories) { if (!Array.isArray(directories)) { if (this.directories.length !== 1) { this.directories = [directories]; } else if (this.directories[0] !== directories) { this.directories[0] = directories; } } else { this.directories = directories; } } close() { this.watcher.close(); } } class Watchpack extends EventEmitter { constructor(options) { super(); if (!options) options = EMPTY_OPTIONS; this.options = options; this.aggregateTimeout = typeof options.aggregateTimeout === "number" ? options.aggregateTimeout : 200; this.watcherOptions = cachedNormalizeOptions(options); this.watcherManager = getWatcherManager(this.watcherOptions); this.fileWatchers = new Map(); this.directoryWatchers = new Map(); this._missing = new Set(); this.startTime = undefined; this.paused = false; this.aggregatedChanges = new Set(); this.aggregatedRemovals = new Set(); this.aggregateTimer = undefined; this._onTimeout = this._onTimeout.bind(this); } watch(arg1, arg2, arg3) { let files, directories, missing, startTime; if (!arg2) { ({ files = EMPTY_ARRAY, directories = EMPTY_ARRAY, missing = EMPTY_ARRAY, startTime } = arg1); } else { files = arg1; directories = arg2; missing = EMPTY_ARRAY; startTime = arg3; } this.paused = false; const fileWatchers = this.fileWatchers; const directoryWatchers = this.directoryWatchers; const ignored = this.watcherOptions.ignored; const filter = path => !ignored(path); const addToMap = (map, key, item) => { const list = map.get(key); if (list === undefined) { map.set(key, item); } else if (Array.isArray(list)) { list.push(item); } else { map.set(key, [list, item]); } }; const fileWatchersNeeded = new Map(); const directoryWatchersNeeded = new Map(); const missingFiles = new Set(); if (this.watcherOptions.followSymlinks) { const resolver = new LinkResolver(); for (const file of files) { if (filter(file)) { for (const innerFile of resolver.resolve(file)) { if (file === innerFile || filter(innerFile)) { addToMap(fileWatchersNeeded, innerFile, file); } } } } for (const file of missing) { if (filter(file)) { for (const innerFile of resolver.resolve(file)) { if (file === innerFile || filter(innerFile)) { missingFiles.add(file); addToMap(fileWatchersNeeded, innerFile, file); } } } } for (const dir of directories) { if (filter(dir)) { let first = true; for (const innerItem of resolver.resolve(dir)) { if (filter(innerItem)) { addToMap( first ? directoryWatchersNeeded : fileWatchersNeeded, innerItem, dir ); } first = false; } } } } else { for (const file of files) { if (filter(file)) { addToMap(fileWatchersNeeded, file, file); } } for (const file of missing) { if (filter(file)) { missingFiles.add(file); addToMap(fileWatchersNeeded, file, file); } } for (const dir of directories) { if (filter(dir)) { addToMap(directoryWatchersNeeded, dir, dir); } } } // Close unneeded old watchers // and update existing watchers for (const [key, w] of fileWatchers) { const needed = fileWatchersNeeded.get(key); if (needed === undefined) { w.close(); fileWatchers.delete(key); } else { w.update(needed); fileWatchersNeeded.delete(key); } } for (const [key, w] of directoryWatchers) { const needed = directoryWatchersNeeded.get(key); if (needed === undefined) { w.close(); directoryWatchers.delete(key); } else { w.update(needed); directoryWatchersNeeded.delete(key); } } // Create new watchers and install handlers on these watchers watchEventSource.batch(() => { for (const [key, files] of fileWatchersNeeded) { const watcher = this.watcherManager.watchFile(key, startTime); if (watcher) { fileWatchers.set(key, new WatchpackFileWatcher(this, watcher, files)); } } for (const [key, directories] of directoryWatchersNeeded) { const watcher = this.watcherManager.watchDirectory(key, startTime); if (watcher) { directoryWatchers.set( key, new WatchpackDirectoryWatcher(this, watcher, directories) ); } } }); this._missing = missingFiles; this.startTime = startTime; } close() { this.paused = true; if (this.aggregateTimer) clearTimeout(this.aggregateTimer); for (const w of this.fileWatchers.values()) w.close(); for (const w of this.directoryWatchers.values()) w.close(); this.fileWatchers.clear(); this.directoryWatchers.clear(); } pause() { this.paused = true; if (this.aggregateTimer) clearTimeout(this.aggregateTimer); } getTimes() { const directoryWatchers = new Set(); addWatchersToSet(this.fileWatchers.values(), directoryWatchers); addWatchersToSet(this.directoryWatchers.values(), directoryWatchers); const obj = Object.create(null); for (const w of directoryWatchers) { const times = w.getTimes(); for (const file of Object.keys(times)) obj[file] = times[file]; } return obj; } getTimeInfoEntries() { const map = new Map(); this.collectTimeInfoEntries(map, map); return map; } collectTimeInfoEntries(fileTimestamps, directoryTimestamps) { const allWatchers = new Set(); addWatchersToSet(this.fileWatchers.values(), allWatchers); addWatchersToSet(this.directoryWatchers.values(), allWatchers); const safeTime = { value: 0 }; for (const w of allWatchers) { w.collectTimeInfoEntries(fileTimestamps, directoryTimestamps, safeTime); } } getAggregated() { if (this.aggregateTimer) { clearTimeout(this.aggregateTimer); this.aggregateTimer = undefined; } const changes = this.aggregatedChanges; const removals = this.aggregatedRemovals; this.aggregatedChanges = new Set(); this.aggregatedRemovals = new Set(); return { changes, removals }; } _onChange(item, mtime, file, type) { file = file || item; if (!this.paused) { this.emit("change", file, mtime, type); if (this.aggregateTimer) clearTimeout(this.aggregateTimer); this.aggregateTimer = setTimeout(this._onTimeout, this.aggregateTimeout); } this.aggregatedRemovals.delete(item); this.aggregatedChanges.add(item); } _onRemove(item, file, type) { file = file || item; if (!this.paused) { this.emit("remove", file, type); if (this.aggregateTimer) clearTimeout(this.aggregateTimer); this.aggregateTimer = setTimeout(this._onTimeout, this.aggregateTimeout); } this.aggregatedChanges.delete(item); this.aggregatedRemovals.add(item); } _onTimeout() { this.aggregateTimer = undefined; const changes = this.aggregatedChanges; const removals = this.aggregatedRemovals; this.aggregatedChanges = new Set(); this.aggregatedRemovals = new Set(); this.emit("aggregated", changes, removals); } } module.exports = Watchpack; watchpack-2.4.0/package.json000066400000000000000000000022031424611751200157500ustar00rootroot00000000000000{ "name": "watchpack", "version": "2.4.0", "description": "", "main": "./lib/watchpack.js", "directories": { "test": "test" }, "files": [ "lib/" ], "scripts": { "pretest": "yarn lint", "test": "mocha", "lint": "eslint lib", "precover": "yarn lint", "pretty-files": "prettier \"lib/**.*\" \"test/**/*.js\" --write", "cover": "istanbul cover node_modules/mocha/bin/_mocha" }, "repository": { "type": "git", "url": "https://github.com/webpack/watchpack.git" }, "author": "Tobias Koppers @sokra", "license": "MIT", "bugs": { "url": "https://github.com/webpack/watchpack/issues" }, "homepage": "https://github.com/webpack/watchpack", "devDependencies": { "coveralls": "^3.0.0", "eslint": "^5.11.1", "eslint-config-prettier": "^4.3.0", "eslint-plugin-prettier": "^3.1.0", "istanbul": "^0.4.3", "mocha": "^5.0.1", "prettier": "^1.11.0", "rimraf": "^2.6.2", "should": "^8.3.1", "write-file-atomic": "^3.0.1" }, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" }, "engines": { "node": ">=10.13.0" } } watchpack-2.4.0/playground/000077500000000000000000000000001424611751200156515ustar00rootroot00000000000000watchpack-2.4.0/playground/watch-folder.js000066400000000000000000000017261424611751200205740ustar00rootroot00000000000000"use strict"; var path = require("path"); var Watchpack = require("../"); var folder = path.join(__dirname, "folder"); function startWatcher(name, files, folders) { var w = new Watchpack({ aggregateTimeout: 3000 }); w.on("change", function(file, mtime) { console.log(name, "change", path.relative(folder, file), mtime); }); w.on("aggregated", function(changes) { var times = w.getTimes(); console.log(name, "aggregated", Array.from(changes, function(file) { return path.relative(folder, file); }), Object.keys(times).reduce(function(obj, file) { obj[path.relative(folder, file)] = times[file]; return obj }, {})); }); var startTime = Date.now() - 10000; console.log(name, startTime); w.watch(files, folders, startTime); } startWatcher("folder", [], [folder]); startWatcher("sub+files", [ path.join(folder, "a.txt"), path.join(folder, "b.txt"), path.join(folder, "c.txt"), path.join(folder, "d.txt"), ], [ path.join(folder, "subfolder") ]); watchpack-2.4.0/test/000077500000000000000000000000001424611751200144445ustar00rootroot00000000000000watchpack-2.4.0/test/Assumption.js000066400000000000000000000240301424611751200171430ustar00rootroot00000000000000/*globals describe it beforeEach afterEach */ "use strict"; require("should"); var path = require("path"); var fs = require("fs"); var TestHelper = require("./helpers/TestHelper"); var fixtures = path.join(__dirname, "fixtures"); var testHelper = new TestHelper(fixtures); const IS_OSX = require("os").platform() === "darwin"; const IS_WIN = require("os").platform() === "win32"; const SUPPORTS_RECURSIVE_WATCHING = IS_OSX || IS_WIN; describe("Assumption", function() { this.timeout(10000); var watcherToClose = null; beforeEach(testHelper.before); afterEach(function(done) { if (watcherToClose) { watcherToClose.close(); watcherToClose = null; } testHelper.after(done); }); it("should have a file system with correct mtime behavior (stats)", function(done) { this.timeout(20000); var i = 60; var count = 60; var minDiffBefore = +Infinity; var maxDiffBefore = -Infinity; var sumDiffBefore = 0; var minDiffAfter = +Infinity; var maxDiffAfter = -Infinity; var sumDiffAfter = 0; testHelper.tick(100, function checkMtime() { var before = Date.now(); testHelper.file("a"); var after = Date.now(); var s = fs.statSync(path.join(fixtures, "a")); var diffBefore = +s.mtime - before; if (diffBefore < minDiffBefore) minDiffBefore = diffBefore; if (diffBefore > maxDiffBefore) maxDiffBefore = diffBefore; sumDiffBefore += diffBefore; var diffAfter = +s.mtime - after; if (diffAfter < minDiffAfter) minDiffAfter = diffAfter; if (diffAfter > maxDiffAfter) maxDiffAfter = diffAfter; sumDiffAfter += diffAfter; if (i-- === 0) { afterMeasure(); } else { testHelper.tick(100, checkMtime); } }); function afterMeasure() { console.log( "mtime stats accuracy (before): [" + minDiffBefore + " ; " + maxDiffBefore + "] avg " + Math.round(sumDiffBefore / count) ); console.log( "mtime stats accuracy (after): [" + minDiffAfter + " ; " + maxDiffAfter + "] avg " + Math.round(sumDiffAfter / count) ); minDiffBefore.should.be.aboveOrEqual(-2000); maxDiffBefore.should.be.below(2000); minDiffAfter.should.be.aboveOrEqual(-2000); maxDiffAfter.should.be.below(2000); done(); } }); it("should have a file system with correct mtime behavior (fs.watch)", function(done) { this.timeout(20000); testHelper.file("a"); var i = 60; var count = 60; var before; var after; var minDiffBefore = +Infinity; var maxDiffBefore = -Infinity; var sumDiffBefore = 0; var minDiffAfter = +Infinity; var maxDiffAfter = -Infinity; var sumDiffAfter = 0; var watcher = (watcherToClose = fs.watch(fixtures)); testHelper.tick(100, function() { watcher.on("change", function(type, filename) { const s = fs.statSync(path.join(fixtures, filename)); if (before && after) { var diffBefore = +s.mtime - before; if (diffBefore < minDiffBefore) minDiffBefore = diffBefore; if (diffBefore > maxDiffBefore) maxDiffBefore = diffBefore; sumDiffBefore += diffBefore; var diffAfter = +s.mtime - after; if (diffAfter < minDiffAfter) minDiffAfter = diffAfter; if (diffAfter > maxDiffAfter) maxDiffAfter = diffAfter; sumDiffAfter += diffAfter; before = after = undefined; if (i-- === 0) { afterMeasure(); } else { testHelper.tick(100, checkMtime); } } }); testHelper.tick(100, checkMtime); }); function checkMtime() { before = Date.now(); testHelper.file("a"); after = Date.now(); } function afterMeasure() { console.log( "mtime fs.watch accuracy (before): [" + minDiffBefore + " ; " + maxDiffBefore + "] avg " + Math.round(sumDiffBefore / count) ); console.log( "mtime fs.watch accuracy (after): [" + minDiffAfter + " ; " + maxDiffAfter + "] avg " + Math.round(sumDiffAfter / count) ); minDiffBefore.should.be.aboveOrEqual(-2000); maxDiffBefore.should.be.below(2000); minDiffAfter.should.be.aboveOrEqual(-2000); maxDiffAfter.should.be.below(2000); done(); } }); if (SUPPORTS_RECURSIVE_WATCHING) { it("should have a file system with correct mtime behavior (fs.watch recursive)", function(done) { this.timeout(20000); testHelper.file("a"); var i = 60; var count = 60; var before; var after; var minDiffBefore = +Infinity; var maxDiffBefore = -Infinity; var sumDiffBefore = 0; var minDiffAfter = +Infinity; var maxDiffAfter = -Infinity; var sumDiffAfter = 0; var watcher = (watcherToClose = fs.watch(fixtures, { recursive: true })); testHelper.tick(100, function() { watcher.on("change", function(type, filename) { const s = fs.statSync(path.join(fixtures, filename)); if (before && after) { var diffBefore = +s.mtime - before; if (diffBefore < minDiffBefore) minDiffBefore = diffBefore; if (diffBefore > maxDiffBefore) maxDiffBefore = diffBefore; sumDiffBefore += diffBefore; var diffAfter = +s.mtime - after; if (diffAfter < minDiffAfter) minDiffAfter = diffAfter; if (diffAfter > maxDiffAfter) maxDiffAfter = diffAfter; sumDiffAfter += diffAfter; before = after = undefined; if (i-- === 0) { afterMeasure(); } else { testHelper.tick(100, checkMtime); } } }); testHelper.tick(100, checkMtime); }); function checkMtime() { before = Date.now(); testHelper.file("a"); after = Date.now(); } function afterMeasure() { console.log( "mtime fs.watch({ recursive: true }) accuracy (before): [" + minDiffBefore + " ; " + maxDiffBefore + "] avg " + Math.round(sumDiffBefore / count) ); console.log( "mtime fs.watch({ recursive: true }) accuracy (after): [" + minDiffAfter + " ; " + maxDiffAfter + "] avg " + Math.round(sumDiffAfter / count) ); minDiffBefore.should.be.aboveOrEqual(-2000); maxDiffBefore.should.be.below(2000); minDiffAfter.should.be.aboveOrEqual(-2000); maxDiffAfter.should.be.below(2000); done(); } }); } it("should not fire events in subdirectories", function(done) { testHelper.dir("watch-test-directory"); testHelper.tick(500, () => { var watcher = (watcherToClose = fs.watch(fixtures)); watcher.on("change", function(arg, arg2) { done(new Error("should not be emitted " + arg + " " + arg2)); done = function() {}; }); watcher.on("error", function(err) { done(err); done = function() {}; }); testHelper.tick(500, function() { testHelper.file("watch-test-directory/watch-test-file"); testHelper.tick(500, function() { done(); }); }); }); }); if (SUPPORTS_RECURSIVE_WATCHING) { it("should fire events in subdirectories (recursive)", function(done) { testHelper.dir("watch-test-directory"); testHelper.file("watch-test-directory/watch-test-file"); testHelper.file("watch-test-directory/existing-file"); testHelper.tick(500, () => { var watcher = (watcherToClose = fs.watch(fixtures, { recursive: true })); const events = []; watcher.once("change", () => { testHelper.tick(1000, function() { events.should.matchAny(/watch-test-directory[/\\]watch-test-file/); done(); }); }); watcher.on("change", function(type, filename) { events.push(filename); }); watcher.on("error", function(err) { done(err); done = function() {}; }); testHelper.tick(500, function() { testHelper.file("watch-test-directory/watch-test-file"); }); }); }); it("should allow to create/close/create recursive watchers", function(done) { testHelper.dir("watch-test-directory"); testHelper.file("watch-test-directory/watch-test-file"); testHelper.file("watch-test-directory/existing-file"); testHelper.tick(500, () => { watcherToClose = fs.watch(fixtures, { recursive: true }); watcherToClose.close(); watcherToClose = fs.watch(fixtures, { recursive: true }); watcherToClose.close(); watcherToClose = fs.watch(fixtures, { recursive: true }); watcherToClose.close(); var watcher = (watcherToClose = fs.watch(fixtures, { recursive: true })); const events = []; watcher.once("change", () => { testHelper.tick(1000, function() { events.should.matchAny(/watch-test-directory[/\\]watch-test-file/); done(); }); }); watcher.on("change", function(type, filename) { events.push(filename); }); watcher.on("error", function(err) { done(err); done = function() {}; }); testHelper.tick(500, function() { testHelper.file("watch-test-directory/watch-test-file"); }); }); }); } if (!IS_OSX) { it("should detect removed directory", function(done) { testHelper.dir("watch-test-dir"); testHelper.tick(() => { var watcher = (watcherToClose = fs.watch( path.join(fixtures, "watch-test-dir") )); let gotSelfRename = false; let gotPermError = false; watcher.on("change", function(type, filename) { if (type === "rename" && filename === "watch-test-dir") gotSelfRename = true; }); watcher.on("error", function(err) { if (err && err.code === "EPERM") gotPermError = true; }); testHelper.tick(500, function() { testHelper.remove("watch-test-dir"); testHelper.tick(3000, function() { if (gotPermError || gotSelfRename) done(); else done(new Error("Didn't receive a event about removed directory")); }); }); }); }); } [100, 200, 300, 500, 700, 1000].reverse().forEach(function(delay) { it("should fire events not after start and " + delay + "ms delay", function( done ) { testHelper.file("watch-test-file-" + delay); testHelper.tick(delay, function() { var watcher = (watcherToClose = fs.watch(fixtures)); watcher.on("change", function(arg) { done(new Error("should not be emitted " + arg)); done = function() {}; }); watcher.on("error", function(err) { done(err); done = function() {}; }); testHelper.tick(500, function() { done(); }); }); }); }); }); watchpack-2.4.0/test/Casing.js000066400000000000000000000061151424611751200162110ustar00rootroot00000000000000/*globals describe it beforeEach afterEach */ "use strict"; require("should"); var path = require("path"); var TestHelper = require("./helpers/TestHelper"); var Watchpack = require("../lib/watchpack"); var fixtures = path.join(__dirname, "fixtures"); var testHelper = new TestHelper(fixtures); var fsIsCaseInsensitive; try { fsIsCaseInsensitive = require("fs").existsSync( path.join(__dirname, "..", "PACKAGE.JSON") ); } catch (e) { fsIsCaseInsensitive = false; } if (fsIsCaseInsensitive) { describe("Casing", function() { this.timeout(10000); beforeEach(testHelper.before); afterEach(testHelper.after); it("should watch a file with the wrong casing", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = 0; w.on("change", function(file) { file.should.be.eql(path.join(fixtures, "a")); changeEvents++; }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "a")]); changeEvents.should.be.greaterThan(0); w.close(); done(); }); w.watch([path.join(fixtures, "a")], []); testHelper.tick(function() { testHelper.file("A"); }); }); it("should mark as missing on changing filename casing (dir watch)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var dir = "case-rename"; var testFile = path.join(dir, "hello.txt"); var testFileRename = path.join(dir, "hEllO.txt"); testHelper.dir(dir); testHelper.file(testFile); w.on("aggregated", function(changes, removals) { const files = w.getTimeInfoEntries(); w.close(); changes.has(path.join(fixtures, dir)).should.be.eql(true); for (const file of files.keys()) { if (file.endsWith("hello.txt")) { return done(new Error(`Renamed file was still in timeInfoEntries`)); } } return done(); }); testHelper.tick(function() { w.watch([], [path.join(fixtures, "case-rename")]); testHelper.tick(function() { testHelper.rename(testFile, testFileRename); }); }); }); it("should mark as missing on changing filename casing (file watch)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var dir = "case-rename"; var testFile = path.join(dir, "hello.txt"); var testFileRename = path.join(dir, "hEllO.txt"); testHelper.dir(dir); testHelper.file(testFile); w.on("aggregated", function(changes, removals) { const files = w.getTimeInfoEntries(); w.close(); changes.has(path.join(fixtures, testFileRename)).should.be.eql(true); removals.has(path.join(fixtures, testFileRename)).should.be.eql(false); for (const file of files.keys()) { if (file.endsWith("hello.txt") && files.get(file)) { return done(new Error(`Renamed file was still in timeInfoEntries`)); } } return done(); }); testHelper.tick(function() { w.watch({ files: [path.join(fixtures, testFile)], missing: [path.join(fixtures, testFileRename)] }); testHelper.tick(function() { testHelper.rename(testFile, testFileRename); }); }); }); }); } watchpack-2.4.0/test/DirectoryWatcher.js000066400000000000000000000113301424611751200202620ustar00rootroot00000000000000/*globals describe it beforeEach afterEach */ "use strict"; require("should"); var path = require("path"); var TestHelper = require("./helpers/TestHelper"); var getWatcherManager = require("../lib/getWatcherManager"); var OrgDirectoryWatcher = require("../lib/DirectoryWatcher"); var fixtures = path.join(__dirname, "fixtures"); var testHelper = new TestHelper(fixtures); var openWatchers = []; var DirectoryWatcher = function(p, options) { var d = new OrgDirectoryWatcher(getWatcherManager(options), p, options); openWatchers.push(d); var orgClose = d.close; d.close = function() { orgClose.call(this); var idx = openWatchers.indexOf(d); if (idx < 0) throw new Error("DirectoryWatcher was already closed"); openWatchers.splice(idx, 1); }; return d; }; describe("DirectoryWatcher", function() { this.timeout(10000); beforeEach(testHelper.before); afterEach(testHelper.after); afterEach(function() { openWatchers.forEach(function(d) { console.log("DirectoryWatcher (" + d.path + ") was not closed."); d.close(); }); }); it("should detect a file creation", function(done) { var d = new DirectoryWatcher(fixtures, {}); var a = d.watch(path.join(fixtures, "a")); a.on("change", function(mtime) { mtime.should.be.type("number"); Object.keys(d.getTimes()) .sort() .should.be.eql([path.join(fixtures, "a")]); a.close(); done(); }); testHelper.tick(function() { testHelper.file("a"); }); }); it("should detect a file change", function(done) { var d = new DirectoryWatcher(fixtures, {}); testHelper.file("a"); testHelper.tick(1000, function() { var a = d.watch(path.join(fixtures, "a")); a.on("change", function(mtime) { mtime.should.be.type("number"); a.close(); done(); }); testHelper.tick(function() { testHelper.file("a"); }); }); }); it("should not detect a file change in initial scan", function(done) { testHelper.file("a"); testHelper.tick(function() { var d = new DirectoryWatcher(fixtures, {}); var a = d.watch(path.join(fixtures, "a")); a.on("change", function() { throw new Error("should not be detected"); }); testHelper.tick(function() { a.close(); done(); }); }); }); it("should detect a file change in initial scan with start date", function(done) { var start = new Date(); testHelper.tick(1000, function() { testHelper.file("a"); testHelper.tick(1000, function() { var d = new DirectoryWatcher(fixtures, {}); var a = d.watch(path.join(fixtures, "a"), start); a.on("change", function() { a.close(); done(); }); }); }); }); it("should not detect a file change in initial scan without start date", function(done) { testHelper.file("a"); testHelper.tick(200, function() { var d = new DirectoryWatcher(fixtures, {}); var a = d.watch(path.join(fixtures, "a")); a.on("change", function(mtime, type) { throw new Error( "should not be detected (" + type + " mtime=" + mtime + " now=" + Date.now() + ")" ); }); testHelper.tick(function() { a.close(); done(); }); }); }); var timings = { slow: 300, fast: 50 }; Object.keys(timings).forEach(function(name) { var time = timings[name]; it("should detect multiple file changes (" + name + ")", function(done) { var d = new DirectoryWatcher(fixtures, {}); testHelper.file("a"); testHelper.tick(function() { var a = d.watch(path.join(fixtures, "a")); var count = 20; var wasChanged = false; a.on("change", function(mtime) { mtime.should.be.type("number"); if (!wasChanged) return; wasChanged = false; if (count-- <= 0) { a.close(); done(); } else { testHelper.tick(time, function() { wasChanged = true; testHelper.file("a"); }); } }); testHelper.tick(function() { wasChanged = true; testHelper.file("a"); }); }); }); }); it("should detect a file removal", function(done) { testHelper.file("a"); var d = new DirectoryWatcher(fixtures, {}); var a = d.watch(path.join(fixtures, "a")); a.on("remove", function() { a.close(); done(); }); testHelper.tick(function() { testHelper.remove("a"); }); }); if (!+process.env.WATCHPACK_POLLING) { it("should log errors emitted from watcher to stderr", function(done) { var error_logged = false; var old_stderr = process.stderr.write; process.stderr.write = function(a) { error_logged = true; }; var d = new DirectoryWatcher(fixtures, {}); var a = d.watch(path.join(fixtures, "a")); d.watcher.emit("error", "error_message"); testHelper.tick(function() { a.close(); process.stderr.write = old_stderr; error_logged.should.be.true(); done(); }); }); } }); watchpack-2.4.0/test/LinkResolver.js000066400000000000000000000006111424611751200174170ustar00rootroot00000000000000/*globals describe it beforeEach afterEach */ "use strict"; const should = require("should"); const LinkResolver = require("../lib/LinkResolver"); describe("LinkResolver", () => { it("should not throw when a path resolves with ENOENT", () => { const resolver = new LinkResolver(); const result = resolver.resolve("/path/to/nonexistent/file/or/folder"); should.exist(result); }); }); watchpack-2.4.0/test/ManyWatchers.js000066400000000000000000000044531424611751200174150ustar00rootroot00000000000000/*globals describe it beforeEach afterEach */ "use strict"; require("should"); const path = require("path"); const TestHelper = require("./helpers/TestHelper"); const Watchpack = require("../lib/watchpack"); const watchEventSource = require("../lib/watchEventSource"); const fixtures = path.join(__dirname, "fixtures"); const testHelper = new TestHelper(fixtures); describe("ManyWatchers", function() { this.timeout(600000); beforeEach(testHelper.before); afterEach(testHelper.after); it("should watch more than 4096 directories", done => { console.time("creating files"); // windows is very slow in creating so many files // this can take about 1 minute const files = []; for (let i = 1; i < 5000; i++) { let highBit = 1; let j = i; while (j > 1) { highBit <<= 1; j >>= 1; } const dir = `${i & highBit}/${i & ~highBit}`; if (i === highBit) { testHelper.dir(`${i}`); testHelper.file(`${i}/file`); files.push(path.join(fixtures, `${i}`, "file")); } testHelper.dir(dir); testHelper.file(`${dir}/file`); files.push(path.join(fixtures, dir, "file")); if (i === highBit) { testHelper.file(`${dir}/file2`); files.push(path.join(fixtures, dir, "file2")); } } testHelper.file("file"); files.push(path.join(fixtures, "file")); console.timeEnd("creating files"); testHelper.tick(10000, () => { const w = new Watchpack({ aggregateTimeout: 1000 }); w.on("aggregated", function(changes) { console.timeEnd("detecting change event"); Array.from(changes).should.be.eql([ path.join(fixtures, "4096/900/file") ]); w.close(); done(); }); console.time("creating/closing watchers"); // MacOS is very slow in creating and destroying watchers // This can take about 2 minutes for (let i = 100; i < files.length; i += 2432) { for (let j = 0; j < files.length - i; j += 987) { w.watch({ files: files.slice(j, j + i) }); } } w.watch({ files }); console.timeEnd("creating/closing watchers"); console.time("calling watch with the same files"); for (let i = 0; i < 2000; i++) { w.watch({ files }); } console.timeEnd("calling watch with the same files"); testHelper.tick(10000, () => { console.time("detecting change event"); testHelper.file("4096/900/file"); }); }); }); }); watchpack-2.4.0/test/Watchpack.js000066400000000000000000001122651424611751200167160ustar00rootroot00000000000000/*globals describe it beforeEach afterEach */ "use strict"; require("should"); var path = require("path"); var TestHelper = require("./helpers/TestHelper"); var Watchpack = require("../lib/watchpack"); var fixtures = path.join(__dirname, "fixtures"); var testHelper = new TestHelper(fixtures); describe("Watchpack", function() { this.timeout(10000); beforeEach(testHelper.before); afterEach(testHelper.after); it("should watch a single file", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = 0; w.on("change", function(file) { file.should.be.eql(path.join(fixtures, "a")); changeEvents++; }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "a")]); changeEvents.should.be.greaterThan(0); w.close(); done(); }); w.watch([path.join(fixtures, "a")], []); testHelper.tick(function() { testHelper.file("a"); }); }); it("should aggregate changes while paused", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); testHelper.file("a"); testHelper.file("b"); w.watch([path.join(fixtures, "a"), path.join(fixtures, "b")], []); testHelper.tick(function() { w.pause(); w.on("change", function(file) { throw new Error("should not be emitted"); }); w.on("aggregated", function(changes) { throw new Error("should not be emitted"); }); testHelper.tick(function() { testHelper.file("a"); testHelper.remove("b"); testHelper.file("b"); testHelper.remove("a"); testHelper.tick(function() { const { changes, removals } = w.getAggregated(); Array.from(changes).should.be.eql([path.join(fixtures, "b")]); Array.from(removals).should.be.eql([path.join(fixtures, "a")]); w.close(); done(); }); }); }); }); it("should not watch a single ignored file (glob)", function(done) { var w = new Watchpack({ aggregateTimeout: 300, ignored: "**/a" }); var changeEvents = 0; var aggregatedEvents = 0; w.on("change", () => { changeEvents++; }); w.on("aggregated", () => { aggregatedEvents++; }); w.watch([path.join(fixtures, "a")], []); testHelper.tick(() => { testHelper.file("a"); testHelper.tick(1000, () => { changeEvents.should.be.eql(0); aggregatedEvents.should.be.eql(0); testHelper.getNumberOfWatchers().should.be.eql(0); w.close(); done(); }); }); }); it("should not watch a single ignored file (regexp)", function(done) { var w = new Watchpack({ aggregateTimeout: 300, ignored: /\/a$/ }); var changeEvents = 0; var aggregatedEvents = 0; w.on("change", () => { changeEvents++; }); w.on("aggregated", () => { aggregatedEvents++; }); w.watch([path.join(fixtures, "a")], []); testHelper.tick(() => { testHelper.file("a"); testHelper.tick(1000, () => { changeEvents.should.be.eql(0); aggregatedEvents.should.be.eql(0); testHelper.getNumberOfWatchers().should.be.eql(0); w.close(); done(); }); }); }); it("should not watch a single ignored file (function)", function(done) { var w = new Watchpack({ aggregateTimeout: 300, ignored: entry => entry.includes("a") }); var changeEvents = 0; var aggregatedEvents = 0; w.on("change", () => { changeEvents++; }); w.on("aggregated", () => { aggregatedEvents++; }); w.watch([path.join(fixtures, "a")], []); testHelper.tick(() => { testHelper.file("a"); testHelper.tick(1000, () => { changeEvents.should.be.eql(0); aggregatedEvents.should.be.eql(0); testHelper.getNumberOfWatchers().should.be.eql(0); w.close(); done(); }); }); }); it("should watch multiple files", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes) .sort() .should.be.eql([path.join(fixtures, "a"), path.join(fixtures, "b")]); changeEvents.should.be.eql([ path.join(fixtures, "a"), path.join(fixtures, "b"), path.join(fixtures, "a"), path.join(fixtures, "b"), path.join(fixtures, "a") ]); Object.keys(w.getTimes()) .sort() .should.be.eql([path.join(fixtures, "a"), path.join(fixtures, "b")]); w.close(); done(); }); w.watch([path.join(fixtures, "a"), path.join(fixtures, "b")], []); testHelper.tick(400, function() { testHelper.file("a"); testHelper.tick(400, function() { testHelper.file("b"); testHelper.tick(400, function() { testHelper.file("a"); testHelper.tick(400, function() { testHelper.file("b"); testHelper.tick(400, function() { testHelper.file("a"); }); }); }); }); }); }); it("should watch a directory", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([path.join(fixtures, "dir", "a")]); w.close(); done(); }); testHelper.dir("dir"); testHelper.tick(200, function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(200, function() { testHelper.file(path.join("dir", "a")); }); }); }); it("should not watch an ignored directory", function(done) { var w = new Watchpack({ aggregateTimeout: 300, ignored: ["**/dir"] }); var changeEvents = 0; var aggregatedEvents = 0; w.on("change", () => { changeEvents++; }); w.on("aggregated", () => { aggregatedEvents++; }); testHelper.dir("dir"); testHelper.tick(200, function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(200, function() { testHelper.file(path.join("dir", "a")); testHelper.tick(1000, function() { changeEvents.should.be.eql(0); aggregatedEvents.should.be.eql(0); testHelper.getNumberOfWatchers().should.be.eql(0); w.close(); done(); }); }); }); }); it("should not watch an ignored file in a directory", function(done) { var w = new Watchpack({ aggregateTimeout: 300, ignored: ["**/a"] }); var changeEvents = 0; var aggregatedEvents = 0; w.on("change", () => { changeEvents++; }); w.on("aggregated", () => { aggregatedEvents++; }); testHelper.dir("dir"); testHelper.tick(200, function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(200, function() { testHelper.file(path.join("dir", "a")); testHelper.tick(1000, function() { changeEvents.should.be.eql(0); aggregatedEvents.should.be.eql(0); w.close(); done(); }); }); }); }); it("should watch a file then a directory", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes, removals) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); Array.from(removals).should.be.eql([]); changeEvents.should.be.eql([path.join(fixtures, "dir", "a")]); w.close(); done(); }); testHelper.dir("dir"); testHelper.dir(path.join("dir", "subdir")); testHelper.file(path.join("dir", "a")); testHelper.tick(400, function() { w.watch([path.join(fixtures, "dir", "a")], []); testHelper.tick(function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(function() { testHelper.file(path.join("dir", "a")); }); }); }); }); it("should watch a directory (delete file)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([path.join(fixtures, "dir", "a")]); w.close(); done(); }); testHelper.dir("dir"); testHelper.file(path.join("dir", "a")); testHelper.tick(function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(function() { testHelper.remove(path.join("dir", "a")); }); }); }); it("should watch a directory (delete and recreate file)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([ path.join(fixtures, "dir", "a"), path.join(fixtures, "dir", "b"), path.join(fixtures, "dir", "a") ]); w.close(); done(); }); testHelper.dir("dir"); testHelper.file(path.join("dir", "a")); testHelper.tick(function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(function() { testHelper.remove(path.join("dir", "a")); testHelper.tick(function() { testHelper.file(path.join("dir", "b")); testHelper.tick(500, function() { testHelper.file(path.join("dir", "a")); }); }); }); }); }); it("should watch a missing directory", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir", "sub")]); changeEvents.should.be.eql([path.join(fixtures, "dir", "sub")]); w.close(); done(); }); testHelper.dir("dir"); testHelper.tick(function() { w.watch({ missing: [path.join(fixtures, "dir", "sub")] }); testHelper.tick(function() { testHelper.dir(path.join("dir", "sub")); }); }); }); it("should watch a directory (add directory)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([path.join(fixtures, "dir", "sub")]); w.close(); done(); }); testHelper.dir("dir"); testHelper.tick(function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(function() { testHelper.dir(path.join("dir", "sub")); }); }); }); it("should watch a directory (delete directory)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); w.close(); done(); }); testHelper.dir("dir"); testHelper.dir(path.join("dir", "sub")); testHelper.file(path.join("dir", "sub", "a")); testHelper.tick(function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(function() { testHelper.remove(path.join("dir", "sub")); }); }); }); it("should watch a directory (delete, restore and change directory)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes, removals) { Array.from(changes).should.be.eql([ path.join(fixtures, "dir", "sub", "a") ]); Array.from(removals).should.be.eql([]); w.close(); done(); }); testHelper.dir("dir"); testHelper.dir(path.join("dir", "sub")); testHelper.file(path.join("dir", "sub", "a")); testHelper.tick(function() { w.watch([path.join(fixtures, "dir", "sub", "a")], []); testHelper.tick(function() { testHelper.remove(path.join("dir", "sub")); testHelper.tick(function() { testHelper.dir(path.join("dir", "sub")); testHelper.file(path.join("dir", "sub", "a")); }); }); }); }); it("should watch a directory (delete directory2)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([path.join(fixtures, "dir", "sub")]); w.close(); done(); }); testHelper.dir("dir"); testHelper.dir(path.join("dir", "sub")); testHelper.tick(function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(function() { testHelper.remove(path.join("dir", "sub")); }); }); }); it("should watch already watched directory", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([path.join(fixtures, "dir", "a")]); w.close(); done(); }); testHelper.dir("dir"); testHelper.file(path.join("dir", "a")); testHelper.tick(400, function() { w.watch([path.join(fixtures, "dir", "a")], []); testHelper.tick(1000, function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(400, function() { testHelper.remove(path.join("dir", "a")); }); }); }); }); it("should watch file in a sub directory", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([path.join(fixtures, "dir", "sub", "a")]); var times = w.getTimeInfoEntries(); const dir = times.get(path.join(fixtures, "dir")); const sub = times.get(path.join(fixtures, "dir", "sub")); const a = times.get(path.join(fixtures, "dir", "sub", "a")); dir.should.be.type("object"); dir.should.have.property("safeTime"); sub.safeTime.should.be.aboveOrEqual(a.safeTime); dir.safeTime.should.be.aboveOrEqual(sub.safeTime); w.close(); done(); }); testHelper.dir("dir"); testHelper.dir(path.join("dir", "sub")); testHelper.tick(function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(function() { testHelper.file(path.join("dir", "sub", "a")); }); }); }); it("should watch file in a sub directory (passed in maps)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([path.join(fixtures, "dir", "sub", "a")]); const files = new Map(); const directories = new Map(); w.collectTimeInfoEntries(files, directories); const dir = directories.get(path.join(fixtures, "dir")); const dirAsFile = files.get(path.join(fixtures, "dir")); const sub = directories.get(path.join(fixtures, "dir", "sub")); const subAsFile = files.get(path.join(fixtures, "dir", "sub")); const a = files.get(path.join(fixtures, "dir", "sub", "a")); const file = files.get(path.join(fixtures, "file")); dir.should.be.type("object"); dir.should.have.property("safeTime"); dirAsFile.should.be.type("object"); dirAsFile.should.not.have.property("safeTime"); sub.should.be.type("object"); sub.should.have.property("safeTime"); subAsFile.should.be.type("object"); subAsFile.should.not.have.property("safeTime"); a.should.be.type("object"); a.should.have.property("safeTime"); a.should.have.property("timestamp"); (file === null).should.be.eql(true); sub.safeTime.should.be.aboveOrEqual(a.safeTime); dir.safeTime.should.be.aboveOrEqual(sub.safeTime); w.close(); done(); }); testHelper.dir("dir"); testHelper.dir(path.join("dir", "sub")); testHelper.dir(path.join("dir", "sub2")); testHelper.tick(function() { w.watch([path.join(fixtures, "file")], [path.join(fixtures, "dir")]); testHelper.tick(function() { testHelper.file(path.join("dir", "sub", "a")); }); }); }); it("should watch directory as file and directory", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); w.on("aggregated", function(changes) { const files = new Map(); const directories = new Map(); w.collectTimeInfoEntries(files, directories); // fixtures should exist const fixturesAsFile = files.get(path.join(fixtures)); fixturesAsFile.should.be.type("object"); // dir should exist const dirAsFile = files.get(path.join(fixtures, "dir")); dirAsFile.should.be.type("object"); dirAsFile.should.not.have.property("safeTime"); // a should have timestamp const a = files.get(path.join(fixtures, "dir", "sub", "a")); a.should.be.type("object"); a.should.have.property("safeTime"); a.should.have.property("timestamp"); // sub should have timestamp const sub = directories.get(path.join(fixtures, "dir", "sub")); sub.should.be.type("object"); sub.should.have.property("safeTime"); // sub should exist as file const subAsFile = files.get(path.join(fixtures, "dir", "sub")); subAsFile.should.be.type("object"); subAsFile.should.not.have.property("safeTime"); w.close(); done(); }); testHelper.dir("dir"); testHelper.dir(path.join("dir", "sub")); testHelper.dir(path.join("dir", "sub2")); testHelper.tick(function() { w.watch( [ path.join(fixtures, "dir", "sub", "a"), path.join(fixtures, "dir", "sub"), path.join(fixtures) ], [path.join(fixtures, "dir", "sub")] ); testHelper.tick(function() { testHelper.file(path.join("dir", "sub", "a")); }); }); }); it("should watch 2 files in a not-existing directory", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); w.on("aggregated", function(changes) { Array.from(changes) .sort() .should.be.eql([ path.join(fixtures, "dir", "sub", "a"), path.join(fixtures, "dir", "sub", "b") ]); w.close(); done(); }); testHelper.dir("dir"); w.watch( [ path.join(fixtures, "dir", "sub", "a"), path.join(fixtures, "dir", "sub", "b") ], [] ); testHelper.tick(function() { testHelper.dir(path.join("dir", "sub")); testHelper.file(path.join("dir", "sub", "a")); testHelper.file(path.join("dir", "sub", "b")); }); }); it("should watch file in a sub sub directory", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([ path.join(fixtures, "dir", "sub", "sub", "a") ]); Object.keys(w.getTimes()) .sort() .should.be.eql([ path.join(fixtures, "dir"), path.join(fixtures, "dir", "sub"), path.join(fixtures, "dir", "sub", "sub"), path.join(fixtures, "dir", "sub", "sub", "a") ]); w.close(); done(); }); testHelper.dir("dir"); testHelper.dir(path.join("dir", "sub")); testHelper.dir(path.join("dir", "sub", "sub")); testHelper.tick(2000, function() { w.watch([], [path.join(fixtures, "dir")], Date.now()); testHelper.tick(function() { testHelper.file(path.join("dir", "sub", "sub", "a")); }); }); }); it("should watch file in a directory that contains special glob characters", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = []; w.on("change", function(file) { if (changeEvents[changeEvents.length - 1] === file) return; changeEvents.push(file); }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "dir")]); changeEvents.should.be.eql([path.join(fixtures, "dir", "sub()", "a")]); var times = w.getTimeInfoEntries(); const dir = times.get(path.join(fixtures, "dir")); const sub = times.get(path.join(fixtures, "dir", "sub()")); const a = times.get(path.join(fixtures, "dir", "sub()", "a")); sub.safeTime.should.be.aboveOrEqual(a.safeTime); dir.safeTime.should.be.aboveOrEqual(sub.safeTime); w.close(); done(); }); testHelper.dir("dir"); testHelper.dir(path.join("dir", "sub()")); testHelper.tick(2000, function() { w.watch([], [path.join(fixtures, "dir")]); testHelper.tick(function() { testHelper.file(path.join("dir", "sub()", "a")); }); }); }); it("should detect a single change to future timestamps", function(done) { const options = { aggregateTimeout: 1000 }; var w = new Watchpack(options); var w2 = new Watchpack(options); w.on("change", function() { throw new Error("should not report change event"); }); w.on("aggregated", function() { throw new Error("should not report aggregated event"); }); testHelper.file("a"); testHelper.tick(400, function() { w2.watch([path.join(fixtures, "a")], [], Date.now()); testHelper.tick(1000, function() { // wait for initial scan testHelper.mtime("a", Date.now() + 1000000); testHelper.tick(400, function() { w.watch([path.join(fixtures, "a")], [], Date.now()); testHelper.tick(1000, function() { w2.close(); w.close(); done(); }); }); }); }); }); it("should create different watchers for different options", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var w2 = new Watchpack({ aggregateTimeout: 1000 }); testHelper.file("a"); testHelper.tick(400, function() { w.watch([path.join(fixtures, "a")], [], Date.now()); w2.watch([path.join(fixtures, "a")], [], Date.now()); testHelper.tick(1000, function() { testHelper.file("a"); testHelper.tick(400, function() { testHelper.file("a"); testHelper.tick(1000, function() { w2.close(); w.close(); done(); }); }); }); }); }); it("should detect a past change to a file (timestamp)", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); var changeEvents = 0; w.on("change", function(file) { file.should.be.eql(path.join(fixtures, "a")); changeEvents++; }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "a")]); changeEvents.should.be.greaterThan(0); w.close(); done(); }); var startTime = Date.now(); testHelper.tick(function() { testHelper.file("a"); testHelper.tick(function() { w.watch([path.join(fixtures, "a")], [], startTime); }); }); }); it("should not detect a past change to a file (watched)", function(done) { var w2 = new Watchpack(); var w = new Watchpack(); w.on("change", function() { throw new Error("Should not be detected"); }); testHelper.tick(function() { testHelper.file("b"); w2.watch([path.join(fixtures, "b")], []); testHelper.tick(1000, function() { // wait for stable state testHelper.file("a"); testHelper.tick(1000, function() { var startTime = Date.now(); testHelper.tick(400, function() { w.watch([path.join(fixtures, "a")], [], startTime); testHelper.tick(1000, function() { w.close(); w2.close(); done(); }); }); }); }); }); }); it("should detect a past change to a file (watched)", function(done) { var w2 = new Watchpack(); var w = new Watchpack(); var changeEvents = 0; w.on("change", function(file) { file.should.be.eql(path.join(fixtures, "a")); changeEvents++; }); w.on("aggregated", function(changes) { Array.from(changes).should.be.eql([path.join(fixtures, "a")]); changeEvents.should.be.eql(1); w.close(); w2.close(); done(); }); testHelper.tick(function() { testHelper.file("b"); w2.watch([path.join(fixtures, "b")], []); testHelper.tick(function() { var startTime = Date.now(); testHelper.tick(function() { testHelper.file("a"); testHelper.tick(400, function() { w.watch([path.join(fixtures, "a")], [], startTime); }); }); }); }); }); it("should watch a single file removal", function(done) { testHelper.file("a"); var w = new Watchpack({ aggregateTimeout: 1000 }); var removeEvents = 0; w.on("remove", function(file) { file.should.be.eql(path.join(fixtures, "a")); removeEvents++; }); w.on("aggregated", function(changes, removals) { Array.from(removals).should.be.eql([path.join(fixtures, "a")]); removeEvents.should.be.eql(1); w.close(); done(); }); testHelper.tick(400, function() { w.watch([path.join(fixtures, "a")], []); testHelper.tick(function() { testHelper.remove("a"); }); }); }); it("should watch multiple file removals", function(done) { var step = 0; testHelper.file("a"); testHelper.file("b"); var w = new Watchpack({ aggregateTimeout: 3000 }); var removeEvents = []; w.on("remove", function(file) { if (removeEvents[removeEvents.length - 1] === file) return; removeEvents.push(file); }); w.on("aggregated", function(changes, removals) { step.should.be.eql(6); Array.from(removals) .sort() .should.be.eql([path.join(fixtures, "a"), path.join(fixtures, "b")]); if (!+process.env.WATCHPACK_POLLING) { removeEvents.should.be.eql([ path.join(fixtures, "a"), path.join(fixtures, "b"), path.join(fixtures, "a"), path.join(fixtures, "b") ]); } Object.keys(w.getTimes()) .sort() .should.be.eql([path.join(fixtures, "a"), path.join(fixtures, "b")]); w.close(); done(); }); testHelper.tick(400, function() { w.watch([path.join(fixtures, "a"), path.join(fixtures, "b")], []); step = 1; testHelper.tick(1000, function() { testHelper.remove("a"); step = 2; testHelper.tick(function() { testHelper.remove("b"); step = 3; testHelper.tick(1000, function() { testHelper.file("a"); testHelper.file("b"); step = 4; testHelper.tick(1000, function() { testHelper.remove("a"); step = 5; testHelper.tick(function() { testHelper.remove("b"); step = 6; }); }); }); }); }); }); }); it("should not report changes in initial scan when no start time is provided", function(done) { var w = new Watchpack({ aggregateTimeout: 100 }); w.on("aggregated", () => { done(new Error("should not fire")); }); testHelper.dir("dir"); testHelper.dir("dir/b"); testHelper.dir("dir/b/sub"); testHelper.file("dir/b/sub/file"); testHelper.dir("dir/b/sub/sub"); testHelper.file("dir/b/sub/sub/file"); testHelper.file("dir/b/file"); testHelper.file("dir/a"); testHelper.tick(1000, () => { w.watch({ directories: [path.join(fixtures, "dir", "b", "sub")] }); testHelper.tick(2000, () => { // no event fired w.watch({ files: [path.join(fixtures, "dir", "a")], directories: [ path.join(fixtures, "dir", "b", "sub"), path.join(fixtures, "dir", "b") ], missing: [path.join(fixtures, "dir", "c")] }); testHelper.tick(2000, () => { // no event fired w.close(); done(); }); }); }); }); it("should not report changes in initial scan when start time is provided", function(done) { var w = new Watchpack({ aggregateTimeout: 100 }); w.on("aggregated", () => { done(new Error("should not fire")); }); testHelper.dir("dir"); testHelper.dir("dir/b"); testHelper.dir("dir/b/sub"); testHelper.file("dir/b/sub/file"); testHelper.dir("dir/b/sub/sub"); testHelper.file("dir/b/sub/sub/file"); testHelper.file("dir/b/file"); testHelper.file("dir/a"); testHelper.tick(1000, () => { w.watch({ directories: [path.join(fixtures, "dir", "b", "sub")], startTime: Date.now() }); testHelper.tick(2000, () => { // no event fired w.watch({ files: [path.join(fixtures, "dir", "a")], directories: [ path.join(fixtures, "dir", "b", "sub"), path.join(fixtures, "dir", "b") ], missing: [path.join(fixtures, "dir", "c")], startTime: Date.now() }); testHelper.tick(2000, () => { // no event fired w.close(); done(); }); }); }); }); it("should not report changes to a folder watched as file when items are added", function(done) { var w = new Watchpack({ aggregateTimeout: 100 }); w.on("aggregated", () => { done(new Error("should not fire")); }); testHelper.dir("dir"); testHelper.file("dir/a"); testHelper.tick(1000, () => { testHelper.file("dir/b"); w.watch({ files: [path.join(fixtures, "dir")], startTime: Date.now() }); testHelper.tick(1000, () => { testHelper.file("dir/c"); testHelper.tick(1000, () => { // no event fired w.close(); done(); }); }); }); }); it("should report removal of file and directory if it is missing in initial scan", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); w.on("aggregated", function(changes, removals) { Array.from(changes).should.be.eql([]); Array.from(removals) .sort() .should.be.eql([ path.join(fixtures, "dir", "a"), path.join(fixtures, "dir", "b") ]); w.close(); done(); }); testHelper.dir("dir"); testHelper.tick(() => { w.watch({ files: [path.join(fixtures, "dir", "a")], directories: [path.join(fixtures, "dir", "b")], missing: [path.join(fixtures, "dir", "c")] }); }); }); it("should report removal of file and directory if parent directory is missing in initial scan", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); w.on("aggregated", function(changes, removals) { Array.from(changes).should.be.eql([]); Array.from(removals) .sort() .should.be.eql([ path.join(fixtures, "dir", "a"), path.join(fixtures, "dir", "b") ]); w.close(); done(); }); testHelper.tick(() => { w.watch({ files: [path.join(fixtures, "dir", "a")], directories: [path.join(fixtures, "dir", "b")], missing: [path.join(fixtures, "dir", "c")] }); }); }); it("should not detect file reading as change, but atomic file writes", done => { var w = new Watchpack({ aggregateTimeout: 1000 }); w.on("aggregated", function(changes, removals) { Array.from(changes) .sort() .should.be.eql([ path.join(fixtures, "dir", "b"), path.join(fixtures, "dir", "c") ]); Array.from(removals).should.be.eql([]); w.close(); done(); }); testHelper.dir("dir"); testHelper.file(path.join("dir", "a")); testHelper.file(path.join("dir", "b")); testHelper.file(path.join("dir", "c")); testHelper.tick(1000, () => { w.watch({ files: [ path.join(fixtures, "dir", "a"), path.join(fixtures, "dir", "b"), path.join(fixtures, "dir", "c") ] }); testHelper.tick(1000, () => { testHelper.accessFile(path.join("dir", "a")); testHelper.fileAtomic(path.join("dir", "b")); testHelper.file(path.join("dir", "c")); }); }); }); it("should allow to reuse watchers when watch is called again", function(done) { var w = new Watchpack({ aggregateTimeout: 1000 }); w.on("aggregated", () => { done(new Error("should not fire")); }); testHelper.dir("dir"); testHelper.dir("dir/b"); testHelper.dir("dir/b/sub"); testHelper.file("dir/b/sub/file"); testHelper.file("dir/b/file"); testHelper.dir("dir/b1"); testHelper.dir("dir/b1/sub"); testHelper.file("dir/b1/sub/file"); testHelper.file("dir/b1/file"); testHelper.dir("dir/b2"); testHelper.dir("dir/b2/sub"); testHelper.file("dir/b2/sub/file"); testHelper.file("dir/b2/file"); testHelper.file("dir/a"); testHelper.file("dir/a1"); testHelper.file("dir/a2"); testHelper.tick(() => { w.watch({ files: [ path.join(fixtures, "dir", "a"), path.join(fixtures, "dir", "a1") ], directories: [ path.join(fixtures, "dir", "b"), path.join(fixtures, "dir", "b1") ], missing: [ path.join(fixtures, "dir", "c"), path.join(fixtures, "dir", "c1") ] }); testHelper.tick(() => { w.watch({ files: [ path.join(fixtures, "dir", "a"), path.join(fixtures, "dir", "a2") ], directories: [ path.join(fixtures, "dir", "b"), path.join(fixtures, "dir", "b2") ], missing: [ path.join(fixtures, "dir", "c"), path.join(fixtures, "dir", "c2") ] }); testHelper.file("dir/b1/sub/file"); testHelper.file("dir/a1"); testHelper.file("dir/c1"); testHelper.tick(2000, () => { // no event fired w.close(); done(); }); }); }); }); let symlinksSupported = false; try { const fs = require("fs"); fs.symlinkSync("helpers", path.join(__dirname, "fixtures"), "dir"); fs.unlinkSync(path.join(__dirname, "fixtures")); symlinksSupported = true; } catch (e) { // ignore } if (symlinksSupported) { describe("symlinks", () => { beforeEach(done => { testHelper.dir("a"); testHelper.dir(path.join("a", "b")); testHelper.file(path.join("a", "b", "c")); testHelper.file(path.join("a", "b", "d")); testHelper.symlinkDir("link", "a"); testHelper.symlinkDir(path.join("a", "link"), "b"); testHelper.symlinkFile(path.join("a", "b", "link"), "c"); testHelper.symlinkFile(path.join("a", "b", "link2"), "link"); testHelper.symlinkFile("link2", "link/link/link2"); testHelper.tick(1000, done); }); function expectWatchEvent(files, dirs, callback, ready) { var w = new Watchpack({ aggregateTimeout: 500, followSymlinks: true }); w.watch([].concat(files), [].concat(dirs), Date.now()); let active = false; let closed = false; w.on("aggregated", changes => { w.close(); closed = true; if (!active) throw new Error("Events are not expected yet"); callback(changes); }); testHelper.tick(1000, () => { if (closed) return; active = true; ready(); }); } it("should detect a change to the original file", function(done) { expectWatchEvent( path.join(fixtures, "link2"), [], changes => { Array.from(changes).should.be.eql([path.join(fixtures, "link2")]); done(); }, () => { testHelper.file(path.join("a", "b", "c")); } ); }); it("should detect a change to the direct symlink", function(done) { expectWatchEvent( path.join(fixtures, "link2"), [], changes => { Array.from(changes).should.be.eql([path.join(fixtures, "link2")]); done(); }, () => { testHelper.unlink("link2"); testHelper.symlinkFile("link2", path.join("a", "b", "d")); } ); }); it("should detect a change to the double symlink", function(done) { expectWatchEvent( path.join(fixtures, "link2"), [], changes => { Array.from(changes).should.be.eql([path.join(fixtures, "link2")]); done(); }, () => { testHelper.unlink(path.join("a", "b", "link2")); testHelper.symlinkFile(path.join("a", "b", "link2"), "d"); } ); }); it("should detect a change to the directory symlink", function(done) { expectWatchEvent( path.join(fixtures, "link2"), [], changes => { Array.from(changes).should.be.eql([path.join(fixtures, "link2")]); done(); }, () => { testHelper.unlink(path.join("a", "link")); testHelper.symlinkDir(path.join("a", "link"), path.join("b", "d")); } ); }); it("should detect a file change in a watched symlinked directory", function(done) { expectWatchEvent( [], path.join(fixtures, "link"), changes => { Array.from(changes).should.be.eql([path.join(fixtures, "link")]); done(); }, () => { testHelper.file(path.join("a", "b", "c")); } ); }); it("should detect a symlink file change in a watched symlinked directory", function(done) { expectWatchEvent( [], path.join(fixtures, "link"), changes => { Array.from(changes).should.be.eql([path.join(fixtures, "link")]); done(); }, () => { testHelper.unlink(path.join("a", "b", "link2")); testHelper.symlinkFile(path.join("a", "b", "link2"), "d"); } ); }); it("should detect a symlink dir change in a watched symlinked directory", function(done) { expectWatchEvent( [], path.join(fixtures, "link"), changes => { Array.from(changes).should.be.eql([path.join(fixtures, "link")]); done(); }, () => { testHelper.unlink(path.join("a", "link")); testHelper.symlinkDir(path.join("a", "link"), path.join("b", "d")); } ); }); }); } else { it("symlinks"); } }); watchpack-2.4.0/test/helpers/000077500000000000000000000000001424611751200161065ustar00rootroot00000000000000watchpack-2.4.0/test/helpers/TestHelper.js000066400000000000000000000067321424611751200205330ustar00rootroot00000000000000"use strict"; var fs = require("fs"); var path = require("path"); var rimraf = require("rimraf"); var writeFileAtomic = require("write-file-atomic"); var watchEventSource = require("../../lib/watchEventSource"); require("../../lib/getWatcherManager"); var watcherManagerModule = require.cache[require.resolve("../../lib/getWatcherManager")]; const allWatcherManager = new Set(); const oldFn = watcherManagerModule.exports; watcherManagerModule = options => { const watcherManager = oldFn(options); allWatcherManager.add(watcherManager); }; const checkAllWatcherClosed = () => { for (const watcherManager of allWatcherManager) { Array.from(watcherManager.directoryWatchers.keys()).should.be.eql([]); } watchEventSource.getNumberOfWatchers().should.be.eql(0); }; function TestHelper(testdir) { this.testdir = testdir; var self = this; this.before = function(done) { self._before(done); }; this.after = function(done) { self._after(done); }; } module.exports = TestHelper; TestHelper.prototype._before = function before(done) { checkAllWatcherClosed(); this.tick( 400, function() { rimraf.sync(this.testdir); fs.mkdirSync(this.testdir); done(); }.bind(this) ); }; TestHelper.prototype._after = function after(done) { var i = 0; this.tick( 300, function del() { try { rimraf.sync(this.testdir); } catch (e) { if (i++ > 20) throw e; this.tick(100, del.bind(this)); return; } checkAllWatcherClosed(); this.tick(300, done); }.bind(this) ); }; TestHelper.prototype.dir = function dir(name) { fs.mkdirSync(path.join(this.testdir, name)); }; TestHelper.prototype.rename = function rename(orig, dest) { fs.renameSync(path.join(this.testdir, orig), path.join(this.testdir, dest)); }; TestHelper.prototype.file = function file(name) { fs.writeFileSync(path.join(this.testdir, name), Math.random() + "", "utf-8"); }; TestHelper.prototype.fileAtomic = function fileAtomic(name) { writeFileAtomic.sync( path.join(this.testdir, name), Math.random() + "", "utf-8" ); }; TestHelper.prototype.accessFile = function accessFile(name) { const stat = fs.statSync(path.join(this.testdir, name)); fs.utimesSync( path.join(this.testdir, name), new Date(Date.now() - 1000 * 60 * 60 * 24), stat.mtime ); fs.readFileSync(path.join(this.testdir, name)); }; TestHelper.prototype.symlinkFile = function symlinkFile(name, target) { fs.symlinkSync(target, path.join(this.testdir, name), "file"); }; TestHelper.prototype.symlinkDir = function symlinkDir(name, target) { fs.symlinkSync(target, path.join(this.testdir, name), "dir"); }; TestHelper.prototype.unlink = function unlink(name) { fs.unlinkSync(path.join(this.testdir, name)); }; TestHelper.prototype.mtime = function mtime(name, mtime) { var stats = fs.statSync(path.join(this.testdir, name)); fs.utimesSync(path.join(this.testdir, name), stats.atime, new Date(mtime)); }; TestHelper.prototype.remove = function remove(name) { rimraf.sync(path.join(this.testdir, name)); }; TestHelper.prototype.tick = function tick(arg, fn) { // if polling is set, ensure the tick is longer than the polling interval. let defaultTick = (+process.env.WATCHPACK_POLLING || 100) + 10; if (typeof arg === "function") { fn = arg; arg = defaultTick; } setTimeout(function() { fn(); }, arg); }; TestHelper.prototype.getNumberOfWatchers = function getNumberOfWatchers() { const count = 0; for (const watcherManager of allWatcherManager) { count += watcherManager.directoryWatchers.size; } return count; }; watchpack-2.4.0/test/mocha.opts000066400000000000000000000000351424611751200164400ustar00rootroot00000000000000--full-trace --reporter spec watchpack-2.4.0/yarn.lock000066400000000000000000001541211424611751200153140ustar00rootroot00000000000000# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 "@babel/code-frame@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== dependencies: "@babel/highlight" "^7.0.0" "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== dependencies: chalk "^2.0.0" esutils "^2.0.2" js-tokens "^4.0.0" abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= acorn-jsx@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== acorn@^6.0.2: version "6.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== ajv@^6.5.3, ajv@^6.5.5, ajv@^6.6.1: version "6.6.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= ansi-escapes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= ansi-regex@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== dependencies: safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== async@1.x: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= dependencies: callsites "^0.2.0" callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= chalk@^2.0.0, chalk@^2.1.0: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0" chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= dependencies: restore-cursor "^2.0.0" cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== dependencies: delayed-stream "~1.0.0" commander@2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= coveralls@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.2.tgz#f5a0bcd90ca4e64e088b710fa8dda640aea4884f" integrity sha512-Tv0LKe/MkBOilH2v7WBiTBdudg2ChfGbdXafc/s330djpF3zKOmuehTeRwjXWc7pzfj9FrDUTA7tEx6Div8NFw== dependencies: growl "~> 1.10.0" js-yaml "^3.11.0" lcov-parse "^0.0.10" log-driver "^1.2.7" minimist "^1.2.0" request "^2.85.0" cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: nice-try "^1.0.4" path-key "^2.0.1" semver "^5.5.0" shebang-command "^1.2.0" which "^1.2.9" dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= dependencies: assert-plus "^1.0.0" debug@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: ms "2.0.0" debug@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= diff@3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= escodegen@1.8.x: version "1.8.1" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= dependencies: esprima "^2.7.1" estraverse "^1.9.1" esutils "^2.0.2" optionator "^0.8.1" optionalDependencies: source-map "~0.2.0" eslint-config-prettier@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-4.3.0.tgz#c55c1fcac8ce4518aeb77906984e134d9eb5a4f0" integrity sha512-sZwhSTHVVz78+kYD3t5pCWSYEdVSBR0PXnwjDRsUs8ytIrK8PLXw+6FKp8r3Z7rx4ZszdetWlXYKOHoUrrwPlA== dependencies: get-stdin "^6.0.0" eslint-plugin-prettier@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz#8695188f95daa93b0dc54b249347ca3b79c4686d" integrity sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA== dependencies: prettier-linter-helpers "^1.0.0" eslint-scope@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" integrity sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA== dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" eslint-utils@^1.3.1: version "1.4.2" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== dependencies: eslint-visitor-keys "^1.0.0" eslint-visitor-keys@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== eslint@^5.11.1: version "5.11.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.11.1.tgz#8deda83db9f354bf9d3f53f9677af7e0e13eadda" integrity sha512-gOKhM8JwlFOc2acbOrkYR05NW8M6DCMSvfcJiBB5NDxRE1gv8kbvxKaC9u69e6ZGEMWXcswA/7eKR229cEIpvg== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.5.3" chalk "^2.1.0" cross-spawn "^6.0.5" debug "^4.0.1" doctrine "^2.1.0" eslint-scope "^4.0.0" eslint-utils "^1.3.1" eslint-visitor-keys "^1.0.0" espree "^5.0.0" esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^2.0.0" functional-red-black-tree "^1.0.1" glob "^7.1.2" globals "^11.7.0" ignore "^4.0.6" imurmurhash "^0.1.4" inquirer "^6.1.0" js-yaml "^3.12.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" lodash "^4.17.5" minimatch "^3.0.4" mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" path-is-inside "^1.0.2" pluralize "^7.0.0" progress "^2.0.0" regexpp "^2.0.1" require-uncached "^1.0.3" semver "^5.5.1" strip-ansi "^4.0.0" strip-json-comments "^2.0.1" table "^5.0.2" text-table "^0.2.0" espree@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.0.tgz#fc7f984b62b36a0f543b13fb9cd7b9f4a7f5b65c" integrity sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA== dependencies: acorn "^6.0.2" acorn-jsx "^5.0.0" eslint-visitor-keys "^1.0.0" esprima@2.7.x, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== dependencies: estraverse "^4.0.0" esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== dependencies: estraverse "^4.1.0" estraverse@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== external-editor@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== dependencies: chardet "^0.7.0" iconv-lite "^0.4.24" tmp "^0.0.33" extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= fast-diff@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= dependencies: escape-string-regexp "^1.0.5" file-entry-cache@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" flat-cache@^1.2.1: version "1.3.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f" integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg== dependencies: circular-json "^0.3.1" graceful-fs "^4.1.2" rimraf "~2.6.2" write "^0.2.1" forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== dependencies: asynckit "^0.4.0" combined-stream "^1.0.6" mime-types "^2.1.12" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== glob@7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= dependencies: inflight "^1.0.4" inherits "2" minimatch "2 || 3" once "^1.3.0" path-is-absolute "^1.0.0" glob@^7.1.2, glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" globals@^11.7.0: version "11.9.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.9.0.tgz#bde236808e987f290768a93d065060d78e6ab249" integrity sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg== graceful-fs@^4.1.2: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== growl@1.10.5, "growl@~> 1.10.0": version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== handlebars@^4.0.1: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== dependencies: minimist "^1.2.5" neo-async "^2.6.0" source-map "^0.6.1" wordwrap "^1.0.0" optionalDependencies: uglify-js "^3.1.4" har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~5.1.0: version "5.1.3" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== dependencies: ajv "^6.5.5" har-schema "^2.0.0" has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" sshpk "^1.7.0" iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" inherits@2: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= inquirer@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" cli-cursor "^2.1.0" cli-width "^2.0.0" external-editor "^3.0.0" figures "^2.0.0" lodash "^4.17.10" mute-stream "0.0.7" run-async "^2.2.0" rxjs "^6.1.0" string-width "^2.1.0" strip-ansi "^5.0.0" through "^2.3.6" is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= istanbul@^0.4.3: version "0.4.5" resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= dependencies: abbrev "1.0.x" async "1.x" escodegen "1.8.x" esprima "2.7.x" glob "^5.0.15" handlebars "^4.0.1" js-yaml "3.x" mkdirp "0.5.x" nopt "3.x" once "1.x" resolve "1.1.x" supports-color "^3.1.0" which "^1.1.1" wordwrap "^1.0.0" js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@3.x, js-yaml@^3.11.0, js-yaml@^3.12.0: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== dependencies: argparse "^1.0.7" esprima "^4.0.0" jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= dependencies: assert-plus "1.0.0" extsprintf "1.3.0" json-schema "0.2.3" verror "1.10.0" lcov-parse@^0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" integrity sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM= levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.5: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== log-driver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== mime-db@~1.37.0: version "1.37.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== mime-types@^2.1.12, mime-types@~2.1.19: version "2.1.21" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== dependencies: mime-db "~1.37.0" mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== "minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" mocha@^5.0.1: version "5.2.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== dependencies: browser-stdout "1.3.1" commander "2.15.1" debug "3.1.0" diff "3.5.0" escape-string-regexp "1.0.5" glob "7.1.2" growl "1.10.5" he "1.1.1" minimatch "3.0.4" mkdirp "0.5.1" supports-color "5.4.0" ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= neo-async@^2.6.0: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== nopt@3.x: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= dependencies: abbrev "1" oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= once@1.x, once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= dependencies: mimic-fn "^1.0.0" optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" levn "~0.3.0" prelude-ls "~1.1.2" type-check "~0.3.2" wordwrap "~1.0.0" os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== dependencies: fast-diff "^1.1.2" prettier@^1.11.0: version "1.17.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.17.1.tgz#ed64b4e93e370cb8a25b9ef7fef3e4fd1c0995db" integrity sha512-TzGRNvuUSmPgwivDqkZ9tM/qTGW9hqDKWOE9YHiyQdixlKbv7kvEqsmDPrcHJTKwthU774TQwZXVtaQ/mMsvjg== progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== psl@^1.1.24: version "1.1.31" resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== request@^2.85.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" caseless "~0.12.0" combined-stream "~1.0.6" extend "~3.0.2" forever-agent "~0.6.1" form-data "~2.3.2" har-validator "~5.1.0" http-signature "~1.2.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" mime-types "~2.1.19" oauth-sign "~0.9.0" performance-now "^2.1.0" qs "~6.5.2" safe-buffer "^5.1.2" tough-cookie "~2.4.3" tunnel-agent "^0.6.0" uuid "^3.3.2" require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= resolve@1.1.x: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= dependencies: onetime "^2.0.0" signal-exit "^3.0.2" rimraf@^2.6.2, rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== dependencies: glob "^7.1.3" run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= dependencies: is-promise "^2.1.0" rxjs@^6.1.0: version "6.3.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" integrity sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw== dependencies: tslib "^1.9.0" safe-buffer@^5.0.1, safe-buffer@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== semver@^5.5.0, semver@^5.5.1: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= should-equal@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-0.8.0.tgz#a3f05732ff45bac1b7ba412f8408856819641299" integrity sha1-o/BXMv9FusG3ukEvhAiFaBlkEpk= dependencies: should-type "0.2.0" should-format@0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/should-format/-/should-format-0.3.2.tgz#a59831e01a2ddee149911bc7148be5c80319e1ff" integrity sha1-pZgx4Bot3uFJkRvHFIvlyAMZ4f8= dependencies: should-type "0.2.0" should-type@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/should-type/-/should-type-0.2.0.tgz#6707ef95529d989dcc098fe0753ab1f9136bb7f6" integrity sha1-ZwfvlVKdmJ3MCY/gdTqx+RNrt/Y= should@^8.3.1: version "8.4.0" resolved "https://registry.yarnpkg.com/should/-/should-8.4.0.tgz#5e60889d3e644bbdd397a30cd34fad28fcf90bc0" integrity sha1-XmCInT5kS73Tl6MM00+tKPz5C8A= dependencies: should-equal "0.8.0" should-format "0.3.2" should-type "0.2.0" signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= slice-ansi@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.0.0.tgz#5373bdb8559b45676e8541c66916cdd6251612e7" integrity sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ== dependencies: ansi-styles "^3.2.0" astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= dependencies: amdefine ">=0.0.4" sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sshpk@^1.7.0: version "1.16.0" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.0.tgz#1d4963a2fbffe58050aa9084ca20be81741c07de" integrity sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" bcrypt-pbkdf "^1.0.0" dashdash "^1.12.0" ecc-jsbn "~0.1.1" getpass "^0.1.1" jsbn "~0.1.0" safer-buffer "^2.0.2" tweetnacl "~0.14.0" string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= dependencies: ansi-regex "^3.0.0" strip-ansi@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== dependencies: ansi-regex "^4.0.0" strip-json-comments@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= supports-color@5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== dependencies: has-flag "^3.0.0" supports-color@^3.1.0: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= dependencies: has-flag "^1.0.0" supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" table@^5.0.2: version "5.1.1" resolved "https://registry.yarnpkg.com/table/-/table-5.1.1.tgz#92030192f1b7b51b6eeab23ed416862e47b70837" integrity sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw== dependencies: ajv "^6.6.1" lodash "^4.17.11" slice-ansi "2.0.0" string-width "^2.1.1" text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== dependencies: psl "^1.1.24" punycode "^1.4.1" tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= dependencies: safe-buffer "^5.0.1" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== dependencies: is-typedarray "^1.0.0" uglify-js@^3.1.4: version "3.13.5" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.5.tgz#5d71d6dbba64cf441f32929b1efce7365bb4f113" integrity sha512-xtB8yEqIkn7zmOyS2zUNBsYCBRhDkvlNxMMY2smuJ/qA8NCHeQvKCF3i9Z4k8FJH4+PJvZRtMrPynfZ75+CSZw== uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== dependencies: punycode "^2.1.0" uuid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" extsprintf "^1.2.0" which@^1.1.1, which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" wordwrap@^1.0.0, wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= write-file-atomic@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.1.tgz#558328352e673b5bb192cf86500d60b230667d4b" integrity sha512-JPStrIyyVJ6oCSz/691fAjFtefZ6q+fP6tm+OS4Qw6o+TGQxNp1ziY2PgS+X/m0V8OWhZiO/m4xSj+Pr4RrZvw== dependencies: imurmurhash "^0.1.4" is-typedarray "^1.0.0" signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= dependencies: mkdirp "^0.5.1"