diff --git a/.travis.yml b/.travis.yml index 5bc96a8..d1af80a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,6 @@ matrix: allow_failures: - os: osx node_js: - - "node" - "12" - "10" - "8" - - "6" diff --git a/README.md b/README.md index 89bb68d..7210442 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ write-file-atomic This is an extension for node's `fs.writeFile` that makes its operation atomic and allows you set ownership (uid/gid of the file). -### var writeFileAtomic = require('write-file-atomic')
writeFileAtomic(filename, data, [options], callback) +### var writeFileAtomic = require('write-file-atomic')
writeFileAtomic(filename, data, [options], [callback]) * filename **String** * data **String** | **Buffer** @@ -15,7 +15,6 @@ atomic and allows you set ownership (uid/gid of the file). * encoding **String** | **Null** default = 'utf8' * fsync **Boolean** default = true * mode **Number** default, from existing file, if any - * Promise **Object** default = native Promise object * callback **Function** Atomically and asynchronously writes data to a file, replacing the file if it already @@ -27,7 +26,7 @@ If writeFile completes successfully then, if passed the **chown** option it will the ownership of the file. Finally it renames the file back to the filename you specified. If it encounters errors at any of these steps it will attempt to unlink the temporary file and then pass the error back to the caller. -If multiple writes are concurrently issued to the same file, the write operations are put into a queue and serialized in the order they were called, using Promises. Native promises are used by default, but you can inject your own promise-like object with the **Promise** option. Writes to different files are still executed in parallel. +If multiple writes are concurrently issued to the same file, the write operations are put into a queue and serialized in the order they were called, using Promises. Writes to different files are still executed in parallel. If provided, the **chown** option requires both **uid** and **gid** properties or else you'll get an error. If **chown** is not specified it will default to using @@ -55,6 +54,20 @@ writeFileAtomic('message.txt', 'Hello Node', {chown:{uid:100,gid:50}}, function }); ``` +This function also supports async/await: + +```javascript +(async () => { + try { + await writeFileAtomic('message.txt', 'Hello Node', {chown:{uid:100,gid:50}}); + console.log('It\'s saved!'); + } catch (err) { + console.error(err); + process.exit(1); + } +})(); +``` + ### var writeFileAtomicSync = require('write-file-atomic').sync
writeFileAtomicSync(filename, data, [options]) The synchronous version of **writeFileAtomic**. Returns the initial diff --git a/index.js b/index.js index 50787d6..7e0a7fe 100644 --- a/index.js +++ b/index.js @@ -4,19 +4,20 @@ module.exports.sync = writeFileSync module.exports._getTmpname = getTmpname // for testing module.exports._cleanupOnExit = cleanupOnExit -var fs = require('fs') -var MurmurHash3 = require('imurmurhash') -var onExit = require('signal-exit') -var path = require('path') -var isTypedArray = require('is-typedarray') -var typedArrayToBuffer = require('typedarray-to-buffer') -var activeFiles = {} +const fs = require('fs') +const MurmurHash3 = require('imurmurhash') +const onExit = require('signal-exit') +const path = require('path') +const isTypedArray = require('is-typedarray') +const typedArrayToBuffer = require('typedarray-to-buffer') +const { promisify } = require('util') +const activeFiles = {} // if we run inside of a worker_thread, `process.pid` is not unique /* istanbul ignore next */ -var threadId = (function getId () { +const threadId = (function getId () { try { - var workerThreads = require('worker_threads') + const workerThreads = require('worker_threads') /// if we are in main thread, this is set to `0` return workerThreads.threadId @@ -26,7 +27,7 @@ var threadId = (function getId () { } })() -var invocations = 0 +let invocations = 0 function getTmpname (filename) { return filename + '.' + MurmurHash3(__filename) @@ -37,149 +38,117 @@ function getTmpname (filename) { } function cleanupOnExit (tmpfile) { - return function () { + return () => { try { fs.unlinkSync(typeof tmpfile === 'function' ? tmpfile() : tmpfile) } catch (_) {} } } -function writeFile (filename, data, options, callback) { - if (options) { - if (options instanceof Function) { - callback = options - options = {} - } else if (typeof options === 'string') { - options = { encoding: options } - } - } else { - options = {} - } - - var Promise = options.Promise || global.Promise - var truename - var fd - var tmpfile - /* istanbul ignore next -- The closure only gets called when onExit triggers */ - var removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile)) - var absoluteName = path.resolve(filename) - - new Promise(function serializeSameFile (resolve) { +function serializeActiveFile (absoluteName) { + return new Promise(resolve => { // make a queue if it doesn't already exist if (!activeFiles[absoluteName]) activeFiles[absoluteName] = [] activeFiles[absoluteName].push(resolve) // add this job to the queue if (activeFiles[absoluteName].length === 1) resolve() // kick off the first one - }).then(function getRealPath () { - return new Promise(function (resolve) { - fs.realpath(filename, function (_, realname) { - truename = realname || filename - tmpfile = getTmpname(truename) - resolve() - }) - }) - }).then(function stat () { - return new Promise(function stat (resolve) { - if (options.mode && options.chown) resolve() - else { - // Either mode or chown is not explicitly set - // Default behavior is to copy it from original file - fs.stat(truename, function (err, stats) { - if (err || !stats) resolve() - else { - options = Object.assign({}, options) - - if (options.mode == null) { - options.mode = stats.mode - } - if (options.chown == null && process.getuid) { - options.chown = { uid: stats.uid, gid: stats.gid } - } - resolve() - } - }) - } - }) - }).then(function thenWriteFile () { - return new Promise(function (resolve, reject) { - fs.open(tmpfile, 'w', options.mode, function (err, _fd) { - fd = _fd - if (err) reject(err) - else resolve() - }) - }) - }).then(function write () { - return new Promise(function (resolve, reject) { - if (isTypedArray(data)) { - data = typedArrayToBuffer(data) - } - if (Buffer.isBuffer(data)) { - fs.write(fd, data, 0, data.length, 0, function (err) { - if (err) reject(err) - else resolve() - }) - } else if (data != null) { - fs.write(fd, String(data), 0, String(options.encoding || 'utf8'), function (err) { - if (err) reject(err) - else resolve() - }) - } else resolve() - }) - }).then(function syncAndClose () { - return new Promise(function (resolve, reject) { - if (options.fsync !== false) { - fs.fsync(fd, function (err) { - if (err) fs.close(fd, () => reject(err)) - else fs.close(fd, resolve) - }) - } else { - fs.close(fd, resolve) + }) +} + +async function writeFileAsync (filename, data, tmpfileStorage, options = {}) { + if (typeof options === 'string') { + options = { encoding: options } + } + + let fd + let tmpfile + /* istanbul ignore next -- The closure only gets called when onExit triggers */ + const removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile)) + const absoluteName = path.resolve(filename) + + try { + await serializeActiveFile(absoluteName) + const truename = await promisify(fs.realpath)(filename).catch(() => filename) + tmpfile = getTmpname(truename) + + if (!options.mode || !options.chown) { + // Either mode or chown is not explicitly set + // Default behavior is to copy it from original file + const stats = await promisify(fs.stat)(truename).catch(() => {}) + if (stats) { + if (options.mode == null) { + options.mode = stats.mode + } + + if (options.chown == null && process.getuid) { + options.chown = { uid: stats.uid, gid: stats.gid } + } } - }) - }).then(function chown () { + } + + fd = await promisify(fs.open)(tmpfile, 'w', options.mode) + if (isTypedArray(data)) { + data = typedArrayToBuffer(data) + } + if (Buffer.isBuffer(data)) { + await promisify(fs.write)(fd, data, 0, data.length, 0) + } else if (data != null) { + await promisify(fs.write)(fd, String(data), 0, String(options.encoding || 'utf8')) + } + + if (options.fsync !== false) { + await promisify(fs.fsync)(fd) + } + fd = null if (options.chown) { - return new Promise(function (resolve, reject) { - fs.chown(tmpfile, options.chown.uid, options.chown.gid, function (err) { - if (err) reject(err) - else resolve() - }) - }) + await promisify(fs.chown)(tmpfile, options.chown.uid, options.chown.gid) } - }).then(function chmod () { + if (options.mode) { - return new Promise(function (resolve, reject) { - fs.chmod(tmpfile, options.mode, function (err) { - if (err) reject(err) - else resolve() - }) - }) + await promisify(fs.chmod)(tmpfile, options.mode) + } + + await promisify(fs.rename)(tmpfile, truename) + + removeOnExitHandler() + } finally { + if (fd) { + await promisify(fs.close)(fd).catch( + /* istanbul ignore next */ + () => {} + ) } - }).then(function rename () { - return new Promise(function (resolve, reject) { - fs.rename(tmpfile, truename, function (err) { - if (err) reject(err) - else resolve() - }) - }) - }).then(function success () { + tmpfileStorage.value = tmpfile removeOnExitHandler() - callback(null, tmpfile) - }, function fail (err) { - return new Promise(resolve => { - return fd ? fs.close(fd, resolve) : resolve() - }).then(() => { - removeOnExitHandler() - fs.unlink(tmpfile, function () { - callback(err, tmpfile) - }) - }) - }).then(function checkQueue () { + await promisify(fs.unlink)(tmpfile).catch(() => {}) activeFiles[absoluteName].shift() // remove the element added by serializeSameFile if (activeFiles[absoluteName].length > 0) { activeFiles[absoluteName][0]() // start next job if one is pending } else delete activeFiles[absoluteName] - }) + } + + return tmpfile +} + +function writeFile (filename, data, options, callback) { + if (options instanceof Function) { + callback = options + options = {} + } + + /* This is so we can provide tmpfile to the callback even in the failure condition. */ + const tmpfileStorage = {} + const promise = writeFileAsync(filename, data, tmpfileStorage, options) + /* istanbul ignore else */ + if (callback) { + promise.then( + tmpfile => callback(null, tmpfile), + err => callback(err, tmpfileStorage.value) + ) + } + + return promise } function writeFileSync (filename, data, options) { @@ -190,13 +159,13 @@ function writeFileSync (filename, data, options) { } catch (ex) { // it's ok, it'll happen on a not yet existing file } - var tmpfile = getTmpname(filename) + const tmpfile = getTmpname(filename) if (!options.mode || !options.chown) { // Either mode or chown is not explicitly set // Default behavior is to copy it from original file try { - var stats = fs.statSync(filename) + const stats = fs.statSync(filename) options = Object.assign({}, options) if (!options.mode) { options.mode = stats.mode @@ -209,9 +178,9 @@ function writeFileSync (filename, data, options) { } } - var fd - var cleanup = cleanupOnExit(tmpfile) - var removeOnExitHandler = onExit(cleanup) + let fd + const cleanup = cleanupOnExit(tmpfile) + const removeOnExitHandler = onExit(cleanup) try { fd = fs.openSync(tmpfile, 'w', options.mode) diff --git a/package-lock.json b/package-lock.json index 0205263..37fc5c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,20 @@ "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } } }, "@babel/helper-function-name": { @@ -80,6 +94,23 @@ "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==", "dev": true }, + "@babel/runtime": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", + "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==", + "dev": true + } + } + }, "@babel/template": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", @@ -128,6 +159,30 @@ "esutils": "^2.0.2", "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@types/prop-types": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.1.tgz", + "integrity": "sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==", + "dev": true + }, + "@types/react": { + "version": "16.8.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.18.tgz", + "integrity": "sha512-lUXdKzRqWR4FebR5tGHkLCqnvQJS4fdXKCBrNGGbglqZg2gpU+J82pMONevQODUotATs9fc9k66bx3/St8vReg==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "csstype": "^2.2.0" } }, "acorn": { @@ -178,6 +233,22 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", + "dev": true + }, + "anymatch": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.0.2.tgz", + "integrity": "sha512-rUe9SxpRQlVg4EM8It7JMNWWYHAirTPpbTuvaSKybb5IejNgWB3PGBBX9rrPKDx2pM/p3Wh+7+ASaWRyyAbxmQ==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "append-transform": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", @@ -218,6 +289,12 @@ "es-abstract": "^1.7.0" } }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -233,12 +310,42 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-hook-domain": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-1.1.0.tgz", + "integrity": "sha512-NH7V97d1yCbIanu2oDLyPT2GFNct0esPeJyRfkk8J5hTztHVSQp4UiNfL2O42sCA9XZPU8OgHvzOmt9ewBhVqA==", + "dev": true, + "requires": { + "source-map-support": "^0.5.11" + } + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, + "auto-bind": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-2.1.0.tgz", + "integrity": "sha512-qZuFvkes1eh9lB2mg8/HG18C+5GIO51r+RrCSst/lh+i5B1CtVlkhTE488M805Nr3dKl0sM/pIFKSKUIlg3zUg==", + "dev": true, + "requires": { + "@types/react": "^16.8.12" + } + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -286,6 +393,265 @@ } } }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-helper-builder-react-jsx": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", + "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "esutils": "^2.0.2" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", + "dev": true + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "babel-plugin-transform-react-jsx": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", + "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", + "dev": true, + "requires": { + "babel-helper-builder-react-jsx": "^6.24.1", + "babel-plugin-syntax-jsx": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -301,6 +667,12 @@ "tweetnacl": "^0.14.3" } }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, "bind-obj-methods": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-2.0.0.tgz", @@ -317,6 +689,15 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", @@ -347,6 +728,23 @@ "integrity": "sha1-uFGGD3Dhlds9J3OVqhp+I+ow7PU=", "dev": true }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } + } + }, "caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -374,6 +772,16 @@ "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", "dev": true }, + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", + "dev": true, + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -417,18 +825,35 @@ "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", "dev": true }, + "chokidar": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.0.tgz", + "integrity": "sha512-ebzWopcacB2J19Jsb5RPtMrzmjUZ5VAQnsL0Ztrix3lswozHbiDp+1Lg3AWSKHdwsps/W2vtshA/x3I827F78g==", + "dev": true, + "requires": { + "anymatch": "^3.0.1", + "async-each": "^1.0.3", + "braces": "^3.0.2", + "fsevents": "^2.0.6", + "glob-parent": "^5.0.0", + "is-binary-path": "^2.1.0", + "is-glob": "^4.0.1", + "normalize-path": "^3.0.0", + "readdirp": "^3.0.1" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, - "clean-yaml-object": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", - "integrity": "sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=", - "dev": true - }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -438,6 +863,16 @@ "restore-cursor": "^2.0.0" } }, + "cli-truncate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-1.1.0.tgz", + "integrity": "sha512-bAtZo0u82gCfaAGfSNxUdTI9mNyza7D8w4CVCcaOsy7sgwDzvx6ekr6cuWJqY3UGzgnQ1+4wgENup5eIhgxEYA==", + "dev": true, + "requires": { + "slice-ansi": "^1.0.0", + "string-width": "^2.0.0" + } + }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", @@ -445,44 +880,22 @@ "dev": true }, "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" } }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -547,6 +960,12 @@ "safe-buffer": "~5.1.1" } }, + "core-js": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.8.tgz", + "integrity": "sha512-RWlREFU74TEkdXzyl1bka66O3kYp8jeTXrvJZDzVVMH8AiHUSOFpL1yfhQJ+wHocAm1m+4971W1PPzfLuCv1vg==", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -609,6 +1028,12 @@ "which": "^1.2.9" } }, + "csstype": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.4.tgz", + "integrity": "sha512-lAJUJP3M6HxFXbqtGRc0iZrdyeN+WzOWeY0q/VnFzI+kqVrYIzC7bWlKqCW7oCIdzoPkvfp82EVvrTlQ8zsWQg==", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -691,10 +1116,19 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", "dev": true }, "doctrine": { @@ -1145,6 +1579,15 @@ "object-assign": "^4.0.1" } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", @@ -1225,6 +1668,12 @@ "locate-path": "^2.0.0" } }, + "findit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", + "integrity": "sha1-ZQnwEmr0wXhVHPqZOU4DLhOk1W4=", + "dev": true + }, "flat-cache": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", @@ -1288,6 +1737,13 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz", + "integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -1350,6 +1806,15 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -1378,14 +1843,6 @@ "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "har-schema": { @@ -1443,6 +1900,16 @@ "is-stream": "^1.0.1" } }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -1475,6 +1942,37 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "import-jsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-jsx/-/import-jsx-2.0.0.tgz", + "integrity": "sha512-xmrgtiRnAdjIaRzKwsHut54FA8nx59WqN4MpQvPFr/8yD6BamavkmKHrA5dotAlnIiF4uqMzg/lA5yhPdpIXsA==", + "dev": true, + "requires": { + "babel-core": "^6.25.0", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-object-rest-spread": "^6.23.0", + "babel-plugin-transform-react-jsx": "^6.24.1", + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "dependencies": { + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1496,6 +1994,80 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "ink": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ink/-/ink-2.2.0.tgz", + "integrity": "sha512-BQl7jpmLxPqFGjdQdgXQS0+mAyn1BHkEW1YXur3dahNNwLB6MWsfAZ1GWVdj+Mbpmj+u33KaFOosw3067t3d9g==", + "dev": true, + "requires": { + "@types/react": "^16.8.6", + "arrify": "^1.0.1", + "auto-bind": "^2.0.0", + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "cli-truncate": "^1.1.0", + "is-ci": "^2.0.0", + "lodash.throttle": "^4.1.1", + "log-update": "^3.0.0", + "prop-types": "^15.6.2", + "react-reconciler": "^0.20.0", + "scheduler": "^0.13.2", + "signal-exit": "^3.0.2", + "slice-ansi": "^1.0.0", + "string-length": "^2.0.0", + "widest-line": "^2.0.0", + "wrap-ansi": "^5.0.0", + "yoga-layout-prebuilt": "^1.9.3" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + } + } + }, "inquirer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", @@ -1517,6 +2089,15 @@ "through": "^2.3.6" } }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", @@ -1529,24 +2110,72 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", "dev": true }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -1644,6 +2273,19 @@ } } }, + "istanbul-lib-processinfo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-1.0.0.tgz", + "integrity": "sha512-FY0cPmWa4WoQNlvB8VOcafiRoB5nB+l2Pz2xGuXHRSy1KM8QFOYfz/rN+bGMCAeejrY3mrpF5oJHcN0s/garCg==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^6.0.5", + "istanbul-lib-coverage": "^2.0.3", + "rimraf": "^2.6.3", + "uuid": "^3.3.2" + } + }, "istanbul-lib-report": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", @@ -1687,12 +2329,6 @@ "requires": { "ms": "^2.1.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -1705,6 +2341,15 @@ "handlebars": "^4.1.2" } }, + "jackspeak": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.0.tgz", + "integrity": "sha512-VDcSunT+wcccoG46FtzuBAyQKlzhHjli4q31e1fIHGOsRspqNUFjVzGb+7eIFDlTvqLygxapDHPHS0ouT2o/tw==", + "dev": true, + "requires": { + "cliui": "^4.1.0" + } + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -1728,9 +2373,9 @@ "dev": true }, "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true }, "json-parse-better-errors": { @@ -1763,6 +2408,12 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -1843,12 +2494,77 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=", + "dev": true + }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", "dev": true }, + "log-update": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-3.2.0.tgz", + "integrity": "sha512-KJ6zAPIHWo7Xg1jYror6IUDFJBq1bQ4Bi4wAEp2y/0ScjBBVi/g0thr0sUVhuvuXauWzczt7T2QHghPDNnKBuw==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "cli-cursor": "^2.1.0", + "wrap-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + } + } + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -1927,14 +2643,6 @@ "dev": true, "requires": { "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "mime-db": { @@ -2048,6 +2756,12 @@ "validate-npm-package-license": "^3.0.1" } }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -2057,6 +2771,12 @@ "path-key": "^2.0.0" } }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, "nyc": { "version": "14.1.1", "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", @@ -2361,6 +3081,12 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "dev": true + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -2439,6 +3165,12 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", @@ -2497,12 +3229,36 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "react": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", + "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.13.6" + } + }, "react-is": { "version": "16.8.6", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==", "dev": true }, + "react-reconciler": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.20.4.tgz", + "integrity": "sha512-kxERc4H32zV2lXMg/iMiwQHOtyqf15qojvkcZ5Ja2CPkjVohHw9k70pdDBwrnQhLVetUJBSYyqU3yqrlVTOajA==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.13.6" + } + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -2540,6 +3296,30 @@ "util-deprecate": "~1.0.1" } }, + "readdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.0.1.tgz", + "integrity": "sha512-emMp13NEwWQQX1yeDgrzDNCSY7NHV6k9HTW0OhyQqOAzYacbqQhnmWiCYjxNPcqMTQ9k77oXQJp28jkytm3+jg==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", + "dev": true, + "requires": { + "esprima": "~4.0.0" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", @@ -2555,6 +3335,15 @@ "es6-error": "^4.0.1" } }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -2684,6 +3473,16 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "scheduler": { + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", + "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", @@ -2716,6 +3515,12 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, "slice-ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", @@ -2726,9 +3531,9 @@ } }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "source-map-support": { @@ -2739,14 +3544,6 @@ "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "spawn-wrap": { @@ -2861,6 +3658,16 @@ } } }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + } + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -2943,51 +3750,58 @@ } }, "tap": { - "version": "12.7.0", - "resolved": "https://registry.npmjs.org/tap/-/tap-12.7.0.tgz", - "integrity": "sha512-SjglJmRv0pqrQQ7d5ZBEY8ZOqv3nYDBXEX51oyycOH7piuhn82JKT/yDNewwmOsodTD/RZL9MccA96EjDgK+Eg==", + "version": "14.1.10", + "resolved": "https://registry.npmjs.org/tap/-/tap-14.1.10.tgz", + "integrity": "sha512-mwYjPJpbnBvwsy1IP12g7UgtvgfnFwIVfeYcI27LDuefFGe1XtW+7+ZgFwu0qHG9f+YCBPMhm82W5o8QggPxkA==", "dev": true, "requires": { + "async-hook-domain": "^1.1.0", "bind-obj-methods": "^2.0.0", "browser-process-hrtime": "^1.0.0", "capture-stack-trace": "^1.0.0", - "clean-yaml-object": "^0.1.0", + "chokidar": "^3.0.0", "color-support": "^1.1.0", - "coveralls": "^3.0.2", + "coveralls": "^3.0.3", + "diff": "^4.0.1", "domain-browser": "^1.2.0", - "esm": "^3.2.5", + "esm": "^3.2.25", + "findit": "^2.0.0", "foreground-child": "^1.3.3", "fs-exists-cached": "^1.0.0", - "function-loop": "^1.0.1", - "glob": "^7.1.3", + "function-loop": "^1.0.2", + "glob": "^7.1.4", + "import-jsx": "^2.0.0", "isexe": "^2.0.0", - "js-yaml": "^3.13.1", + "istanbul-lib-processinfo": "^1.0.0", + "jackspeak": "^1.4.0", "minipass": "^2.3.5", "mkdirp": "^0.5.1", - "nyc": "^14.0.0", + "nyc": "^14.1.1", "opener": "^1.5.1", - "os-homedir": "^1.0.2", "own-or": "^1.0.0", "own-or-env": "^1.0.1", "rimraf": "^2.6.3", "signal-exit": "^3.0.0", - "source-map-support": "^0.5.10", + "source-map-support": "^0.5.12", "stack-utils": "^1.0.2", - "tap-mocha-reporter": "^3.0.9", - "tap-parser": "^7.0.0", - "tmatch": "^4.0.0", + "tap-mocha-reporter": "^4.0.1", + "tap-parser": "^9.3.2", + "tap-yaml": "^1.0.0", + "tcompare": "^2.3.0", + "treport": "^0.4.0", "trivial-deferred": "^1.0.1", - "ts-node": "^8.0.2", - "tsame": "^2.0.1", - "typescript": "^3.3.3", + "ts-node": "^8.1.0", + "typescript": "^3.4.5", + "which": "^1.3.1", "write-file-atomic": "^2.4.2", + "yaml": "^1.6.0", "yapool": "^1.0.0" } }, "tap-mocha-reporter": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-3.0.9.tgz", - "integrity": "sha512-VO07vhC9EG27EZdOe7bWBj1ldbK+DL9TnRadOgdQmiQOVZjFpUEQuuqO7+rNSO2kfmkq5hWeluYXDWNG/ytXTQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-4.0.1.tgz", + "integrity": "sha512-/KfXaaYeSPn8qBi5Be8WSIP3iKV83s2uj2vzImJAXmjNu22kzqZ+1Dv1riYWa53sPCiyo1R1w1jbJrftF8SpcQ==", "dev": true, "requires": { "color-support": "^1.1.0", @@ -2995,9 +3809,9 @@ "diff": "^1.3.2", "escape-string-regexp": "^1.0.3", "glob": "^7.0.5", - "js-yaml": "^3.3.1", "readable-stream": "^2.1.5", - "tap-parser": "^5.1.0", + "tap-parser": "^8.0.0", + "tap-yaml": "0 || 1", "unicode-length": "^1.0.0" }, "dependencies": { @@ -3010,6 +3824,12 @@ "ms": "2.0.0" } }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -3017,29 +3837,44 @@ "dev": true }, "tap-parser": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-5.4.0.tgz", - "integrity": "sha512-BIsIaGqv7uTQgTW1KLTMNPSEQf4zDDPgYOBRdgOfuB+JFOLRBfEu6cLa/KvMvmqggu1FKXDfitjLwsq4827RvA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-8.1.0.tgz", + "integrity": "sha512-GgOzgDwThYLxhVR83RbS1JUR1TxcT+jfZsrETgPAvFdr12lUOnuvrHOBaUQgpkAp6ZyeW6r2Nwd91t88M0ru3w==", "dev": true, "requires": { "events-to-array": "^1.0.1", - "js-yaml": "^3.2.7", - "readable-stream": "^2" + "minipass": "^2.2.0", + "tap-yaml": "0 || 1" } } } }, "tap-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-7.0.0.tgz", - "integrity": "sha512-05G8/LrzqOOFvZhhAk32wsGiPZ1lfUrl+iV7+OkKgfofZxiceZWMHkKmow71YsyVQ8IvGBP2EjcIjE5gL4l5lA==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-9.3.2.tgz", + "integrity": "sha512-bQ76sD6ZP9loxdk/KiqXgWDEfjJYiZUj0a7ElnLMSny7Q8G72UMcOQee85j5ddKHA9fzGAoL6cfJbg3rur7S5g==", "dev": true, "requires": { "events-to-array": "^1.0.1", - "js-yaml": "^3.2.7", - "minipass": "^2.2.0" + "minipass": "^2.2.0", + "tap-yaml": "^1.0.0" + } + }, + "tap-yaml": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.0.tgz", + "integrity": "sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ==", + "dev": true, + "requires": { + "yaml": "^1.5.0" } }, + "tcompare": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-2.3.0.tgz", + "integrity": "sha512-fAfA73uFtFGybWGt4+IYT6UPLYVZQ4NfsP+IXEZGY0vh8e2IF7LVKafcQNMRBLqP0wzEA65LM9Tqj+FSmO8GLw==", + "dev": true + }, "test-exclude": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", @@ -3167,12 +4002,6 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "tmatch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-4.0.0.tgz", - "integrity": "sha512-Ynn2Gsp+oCvYScQXeV+cCs7citRDilq0qDXA6tuvFwDgiYyyaq7D5vKUlAPezzZR5NDobc/QMeN6e5guOYmvxg==", - "dev": true - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -3183,11 +4012,20 @@ } }, "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "dev": true }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -3206,6 +4044,44 @@ } } }, + "treport": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/treport/-/treport-0.4.0.tgz", + "integrity": "sha512-1/gjl3sCJAm60txV3uyz/bghxkzXidSvijM15dM+xgtBRXnZ/5Lwzb6SY1AvhRzTl+rOsukw9kDh2mjTtm6L9A==", + "dev": true, + "requires": { + "cardinal": "^2.1.1", + "chalk": "^2.4.2", + "import-jsx": "^2.0.0", + "ink": "^2.1.1", + "ms": "^2.1.1", + "react": "^16.8.6", + "string-length": "^2.0.0", + "tap-parser": "^9.3.2", + "unicode-length": "^2.0.1" + }, + "dependencies": { + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "unicode-length": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-length/-/unicode-length-2.0.1.tgz", + "integrity": "sha1-hN3DCcIyNjX2QuhtRI6ersCEwEo=", + "dev": true, + "requires": { + "punycode": "^2.0.0", + "strip-ansi": "^3.0.1" + } + } + } + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -3239,12 +4115,6 @@ } } }, - "tsame": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/tsame/-/tsame-2.0.1.tgz", - "integrity": "sha512-jxyxgKVKa4Bh5dPcO42TJL22lIvfd9LOVJwdovKOnJa4TLLrHxquK+DlGm4rkGmrcur+GRx+x4oW00O2pY/fFw==", - "dev": true - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -3292,15 +4162,6 @@ "requires": { "commander": "~2.20.0", "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } } }, "unicode-length": { @@ -3394,6 +4255,15 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "requires": { + "string-width": "^2.1.1" + } + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -3401,49 +4271,42 @@ "dev": true }, "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "color-convert": "^1.9.0" + "number-is-nan": "^1.0.0" } }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^2.0.0" } } } @@ -3492,6 +4355,15 @@ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, + "yaml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.6.0.tgz", + "integrity": "sha512-iZfse3lwrJRoSlfs/9KQ9iIXxs9++RvBFVzAqbbBiFT+giYtyanevreF9r61ZTbGMgWQBxAua3FzJiniiJXWWw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.5" + } + }, "yapool": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yapool/-/yapool-1.0.0.tgz", @@ -3523,6 +4395,26 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -3585,6 +4477,17 @@ "requires": { "ansi-regex": "^4.1.0" } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } } } }, @@ -3603,6 +4506,12 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz", "integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==", "dev": true + }, + "yoga-layout-prebuilt": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/yoga-layout-prebuilt/-/yoga-layout-prebuilt-1.9.3.tgz", + "integrity": "sha512-9SNQpwuEh2NucU83i2KMZnONVudZ86YNcFk9tq74YaqrQfgJWO3yB9uzH1tAg8iqh5c9F5j0wuyJ2z72wcum2w==", + "dev": true } } } diff --git a/package.json b/package.json index ec7d3ab..8030e12 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "require-inject": "^1.4.4", "rimraf": "^2.6.3", "standard": "^12.0.1", - "tap": "^12.7.0" + "tap": "^14.1.1" }, "files": [ "index.js" diff --git a/test/basic.js b/test/basic.js index 499ad53..2d9e084 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,217 +1,209 @@ 'use strict' -var test = require('tap').test -var requireInject = require('require-inject') +const { test } = require('tap') +const requireInject = require('require-inject') -var unlinked = [] -var writeFileAtomic = requireInject('../index', { +let unlinked = [] +const writeFileAtomic = requireInject('../index', { 'fs': { - realpath: function (filename, cb) { + realpath (filename, cb) { return cb(null, filename) }, - open: function (tmpfile, options, mode, cb) { + open (tmpfile, options, mode, cb) { if (/noopen/.test(tmpfile)) return cb(new Error('ENOOPEN')) cb(null, tmpfile) }, - write: function (fd) { - var cb = arguments[arguments.length - 1] + write (fd) { + const cb = arguments[arguments.length - 1] if (/nowrite/.test(fd)) return cb(new Error('ENOWRITE')) cb() }, - fsync: function (fd, cb) { + fsync (fd, cb) { if (/nofsync/.test(fd)) return cb(new Error('ENOFSYNC')) cb() }, - close: function (fd, cb) { cb() }, - chown: function (tmpfile, uid, gid, cb) { + close (fd, cb) { cb() }, + chown (tmpfile, uid, gid, cb) { if (/nochown/.test(tmpfile)) return cb(new Error('ENOCHOWN')) cb() }, - chmod: function (tmpfile, mode, cb) { + chmod (tmpfile, mode, cb) { if (/nochmod/.test(tmpfile)) return cb(new Error('ENOCHMOD')) cb() }, - rename: function (tmpfile, filename, cb) { + rename (tmpfile, filename, cb) { if (/norename/.test(tmpfile)) return cb(new Error('ENORENAME')) cb() }, - unlink: function (tmpfile, cb) { + unlink (tmpfile, cb) { if (/nounlink/.test(tmpfile)) return cb(new Error('ENOUNLINK')) cb() }, - stat: function (tmpfile, cb) { + stat (tmpfile, cb) { if (/nostat/.test(tmpfile)) return cb(new Error('ENOSTAT')) cb() }, - realpathSync: function (filename, cb) { + realpathSync (filename, cb) { return filename }, - openSync: function (tmpfile, options) { + openSync (tmpfile, options) { if (/noopen/.test(tmpfile)) throw new Error('ENOOPEN') return tmpfile }, - writeSync: function (fd) { + writeSync (fd) { if (/nowrite/.test(fd)) throw new Error('ENOWRITE') }, - fsyncSync: function (fd) { + fsyncSync (fd) { if (/nofsync/.test(fd)) throw new Error('ENOFSYNC') }, - closeSync: function () { }, - chownSync: function (tmpfile, uid, gid) { + closeSync () { }, + chownSync (tmpfile, uid, gid) { if (/nochown/.test(tmpfile)) throw new Error('ENOCHOWN') }, - chmodSync: function (tmpfile, mode) { + chmodSync (tmpfile, mode) { if (/nochmod/.test(tmpfile)) throw new Error('ENOCHMOD') }, - renameSync: function (tmpfile, filename) { + renameSync (tmpfile, filename) { if (/norename/.test(tmpfile)) throw new Error('ENORENAME') }, - unlinkSync: function (tmpfile) { + unlinkSync (tmpfile) { if (/nounlink/.test(tmpfile)) throw new Error('ENOUNLINK') unlinked.push(tmpfile) }, - statSync: function (tmpfile) { + statSync (tmpfile) { if (/nostat/.test(tmpfile)) throw new Error('ENOSTAT') } } }) -var writeFileAtomicSync = writeFileAtomic.sync +const writeFileAtomicSync = writeFileAtomic.sync -test('getTmpname', function (t) { - var getTmpname = writeFileAtomic._getTmpname - var a = getTmpname('abc.def') - var b = getTmpname('abc.def') +test('getTmpname', t => { + const getTmpname = writeFileAtomic._getTmpname + const a = getTmpname('abc.def') + const b = getTmpname('abc.def') t.notEqual(a, b, 'different invocations of getTmpname get different results') t.done() }) -test('cleanupOnExit', function (t) { - var file = 'tmpname' +test('cleanupOnExit', t => { + const file = 'tmpname' unlinked = [] - var cleanup = writeFileAtomic._cleanupOnExit(() => file) + const cleanup = writeFileAtomic._cleanupOnExit(() => file) cleanup() t.isDeeply(unlinked, [file], 'cleanup code unlinks') - var cleanup2 = writeFileAtomic._cleanupOnExit('nounlink') + const cleanup2 = writeFileAtomic._cleanupOnExit('nounlink') t.doesNotThrow(cleanup2, 'exceptions are caught') unlinked = [] t.done() }) -test('async tests', function (t) { +test('async tests', t => { t.plan(17) - writeFileAtomic('good', 'test', { mode: '0777' }, function (err) { + writeFileAtomic('good', 'test', { mode: '0777' }, err => { t.notOk(err, 'No errors occur when passing in options') }) - writeFileAtomic('good', 'test', 'utf8', function (err) { + writeFileAtomic('good', 'test', 'utf8', err => { t.notOk(err, 'No errors occur when passing in options as string') }) - writeFileAtomic('good', 'test', undefined, function (err) { + writeFileAtomic('good', 'test', undefined, err => { t.notOk(err, 'No errors occur when NOT passing in options') }) - writeFileAtomic('good', 'test', function (err, tmpfile) { + writeFileAtomic('good', 'test', (err, tmpfile) => { t.notOk(err) t.match(tmpfile, /^good\.\d+$/, 'Provides tmpfile in callback upon success') }) - writeFileAtomic('noopen', 'test', function (err) { + writeFileAtomic('noopen', 'test', err => { t.is(err && err.message, 'ENOOPEN', 'fs.open failures propagate') }) - writeFileAtomic('nowrite', 'test', function (err) { + writeFileAtomic('nowrite', 'test', err => { t.is(err && err.message, 'ENOWRITE', 'fs.writewrite failures propagate') }) - writeFileAtomic('nowrite', Buffer.from('test', 'utf8'), function (err) { + writeFileAtomic('nowrite', Buffer.from('test', 'utf8'), err => { t.is(err && err.message, 'ENOWRITE', 'fs.writewrite failures propagate for buffers') }) - writeFileAtomic('nochown', 'test', { chown: { uid: 100, gid: 100 } }, function (err) { + writeFileAtomic('nochown', 'test', { chown: { uid: 100, gid: 100 } }, err => { t.is(err && err.message, 'ENOCHOWN', 'Chown failures propagate') }) - writeFileAtomic('nochown', 'test', function (err) { + writeFileAtomic('nochown', 'test', err => { t.notOk(err, 'No attempt to chown when no uid/gid passed in') }) - writeFileAtomic('nochmod', 'test', { mode: parseInt('741', 8) }, function (err) { + writeFileAtomic('nochmod', 'test', { mode: parseInt('741', 8) }, err => { t.is(err && err.message, 'ENOCHMOD', 'Chmod failures propagate') }) - writeFileAtomic('nofsyncopt', 'test', { fsync: false }, function (err) { + writeFileAtomic('nofsyncopt', 'test', { fsync: false }, err => { t.notOk(err, 'fsync skipped if options.fsync is false') }) - writeFileAtomic('norename', 'test', function (err) { + writeFileAtomic('norename', 'test', err => { t.is(err && err.message, 'ENORENAME', 'Rename errors propagate') }) - writeFileAtomic('norename nounlink', 'test', function (err) { + writeFileAtomic('norename nounlink', 'test', err => { t.is(err && err.message, 'ENORENAME', 'Failure to unlink the temp file does not clobber the original error') }) - writeFileAtomic('nofsync', 'test', function (err) { + writeFileAtomic('nofsync', 'test', err => { t.is(err && err.message, 'ENOFSYNC', 'Fsync failures propagate') }) - writeFileAtomic('noopen', 'test', function (err, tmpfile) { + writeFileAtomic('noopen', 'test', (err, tmpfile) => { t.ok(err) t.match(tmpfile, /^noopen\.\d+$/, 'Provides tmpfile in callback upon failure') }) }) -test('sync tests', function (t) { +test('sync tests', t => { t.plan(14) - var throws = function (shouldthrow, msg, todo) { - var err + const throws = function (shouldthrow, msg, todo) { + let err try { todo() } catch (e) { err = e } t.is(shouldthrow, err && err.message, msg) } - var noexception = function (msg, todo) { - var err + const noexception = function (msg, todo) { + let err try { todo() } catch (e) { err = e } t.ifError(err, msg) } - noexception('No errors occur when passing in options', function () { + noexception('No errors occur when passing in options', () => { writeFileAtomicSync('good', 'test', { mode: '0777' }) }) - noexception('No errors occur when passing in options as string', function () { + noexception('No errors occur when passing in options as string', () => { writeFileAtomicSync('good', 'test', 'utf8') }) - noexception('No errors occur when NOT passing in options', function () { + noexception('No errors occur when NOT passing in options', () => { writeFileAtomicSync('good', 'test') }) - noexception('Returns tmpfile upon success', function () { + noexception('Returns tmpfile upon success', () => { t.match(writeFileAtomicSync('good', 'test'), /^good\.\d+$/) }) - noexception('fsync never called if options.fsync is falsy', function () { + noexception('fsync never called if options.fsync is falsy', () => { writeFileAtomicSync('good', 'test', { fsync: false }) }) - throws('ENOWRITE', 'fs.writeSync failures propagate', function () { + throws('ENOWRITE', 'fs.writeSync failures propagate', () => { writeFileAtomicSync('nowrite', 'test') }) - throws('ENOOPEN', 'fs.openSync failures propagate', function () { + throws('ENOOPEN', 'fs.openSync failures propagate', () => { writeFileAtomicSync('noopen', 'test') }) - throws('ENOCHOWN', 'Chown failures propagate', function () { + throws('ENOCHOWN', 'Chown failures propagate', () => { writeFileAtomicSync('nochown', 'test', { chown: { uid: 100, gid: 100 } }) }) - noexception('No attempt to chown when false passed in', function () { + noexception('No attempt to chown when false passed in', () => { writeFileAtomicSync('nochown', 'test', { chown: false }) }) - noexception('No errors occured when chown is undefined and original file owner used', function () { + noexception('No errors occured when chown is undefined and original file owner used', () => { writeFileAtomicSync('chowncopy', 'test', { chown: undefined }) }) - throws('ENORENAME', 'Rename errors propagate', function () { + throws('ENORENAME', 'Rename errors propagate', () => { writeFileAtomicSync('norename', 'test') }) - throws('ENORENAME', 'Failure to unlink the temp file does not clobber the original error', function () { + throws('ENORENAME', 'Failure to unlink the temp file does not clobber the original error', () => { writeFileAtomicSync('norename nounlink', 'test') }) - throws('ENOFSYNC', 'Fsync errors propagate', function () { + throws('ENOFSYNC', 'Fsync errors propagate', () => { writeFileAtomicSync('nofsync', 'test') }) }) -test('promise injection', function (t) { - t.plan(2) - var usedCustomPromise = false - class customPromise extends Promise { - then () { - usedCustomPromise = true - return super.then.apply(this, arguments) - } - } - writeFileAtomic('good', 'test', { Promise: customPromise }, function (err) { - t.notOk(err, 'no errors occur when providing customPromise') - t.true(usedCustomPromise, 'the custom promise was injected and used') - }) +test('promise', async t => { + const tmpfile = await writeFileAtomic('good', 'test') + t.match(tmpfile, /^good\.\d+$/, 'resolves tmpfile upon success') + + await t.rejects(writeFileAtomic('noopen', 'test')) }) diff --git a/test/concurrency.js b/test/concurrency.js index e2eeb80..de6c2f2 100644 --- a/test/concurrency.js +++ b/test/concurrency.js @@ -1,136 +1,136 @@ 'use strict' -var test = require('tap').test -var requireInject = require('require-inject') +const { test } = require('tap') +const requireInject = require('require-inject') // defining mock for fs so its functions can be modified -var fs = { - realpath: function (filename, cb) { +const fs = { + realpath (filename, cb) { return cb(null, filename) }, - open: function (tmpfile, options, mode, cb) { + open (tmpfile, options, mode, cb) { if (/noopen/.test(tmpfile)) return cb(new Error('ENOOPEN')) cb(null, tmpfile) }, - write: function (fd) { - var cb = arguments[arguments.length - 1] + write (fd) { + const cb = arguments[arguments.length - 1] if (/nowrite/.test(fd)) return cb(new Error('ENOWRITE')) cb() }, - fsync: function (fd, cb) { + fsync (fd, cb) { if (/nofsync/.test(fd)) return cb(new Error('ENOFSYNC')) cb() }, - close: function (fd, cb) { cb() }, - chown: function (tmpfile, uid, gid, cb) { + close (fd, cb) { cb() }, + chown (tmpfile, uid, gid, cb) { if (/nochown/.test(tmpfile)) return cb(new Error('ENOCHOWN')) cb() }, - chmod: function (tmpfile, mode, cb) { + chmod (tmpfile, mode, cb) { if (/nochmod/.test(tmpfile)) return cb(new Error('ENOCHMOD')) cb() }, - rename: function (tmpfile, filename, cb) { + rename (tmpfile, filename, cb) { if (/norename/.test(tmpfile)) return cb(new Error('ENORENAME')) cb() }, - unlink: function (tmpfile, cb) { + unlink (tmpfile, cb) { if (/nounlink/.test(tmpfile)) return cb(new Error('ENOUNLINK')) cb() }, - stat: function (tmpfile, cb) { + stat (tmpfile, cb) { if (/nostat/.test(tmpfile)) return cb(new Error('ENOSTAT')) cb() }, - realpathSync: function (filename, cb) { + realpathSync (filename, cb) { return filename }, - openSync: function (tmpfile, options) { + openSync (tmpfile, options) { if (/noopen/.test(tmpfile)) throw new Error('ENOOPEN') return tmpfile }, - writeSync: function (fd) { + writeSync (fd) { if (/nowrite/.test(fd)) throw new Error('ENOWRITE') }, - fsyncSync: function (fd) { + fsyncSync (fd) { if (/nofsync/.test(fd)) throw new Error('ENOFSYNC') }, - closeSync: function () { }, - chownSync: function (tmpfile, uid, gid) { + closeSync () { }, + chownSync (tmpfile, uid, gid) { if (/nochown/.test(tmpfile)) throw new Error('ENOCHOWN') }, - chmodSync: function (tmpfile, mode) { + chmodSync (tmpfile, mode) { if (/nochmod/.test(tmpfile)) throw new Error('ENOCHMOD') }, - renameSync: function (tmpfile, filename) { + renameSync (tmpfile, filename) { if (/norename/.test(tmpfile)) throw new Error('ENORENAME') }, - unlinkSync: function (tmpfile) { + unlinkSync (tmpfile) { if (/nounlink/.test(tmpfile)) throw new Error('ENOUNLINK') }, - statSync: function (tmpfile) { + statSync (tmpfile) { if (/nostat/.test(tmpfile)) throw new Error('ENOSTAT') } } -var writeFileAtomic = requireInject('../index', { +const writeFileAtomic = requireInject('../index', { 'fs': fs }) // preserve original functions -var oldRealPath = fs.realpath -var oldRename = fs.rename +const oldRealPath = fs.realpath +const oldRename = fs.rename -test('ensure writes to the same file are serial', function (t) { - var fileInUse = false - var ops = 5 // count for how many concurrent write ops to request +test('ensure writes to the same file are serial', t => { + let fileInUse = false + let ops = 5 // count for how many concurrent write ops to request t.plan(ops * 3 + 3) - fs.realpath = function () { + fs.realpath = (...args) => { t.false(fileInUse, 'file not in use') fileInUse = true - oldRealPath.apply(writeFileAtomic, arguments) + oldRealPath(...args) } - fs.rename = function () { + fs.rename = (...args) => { t.true(fileInUse, 'file in use') fileInUse = false - oldRename.apply(writeFileAtomic, arguments) + oldRename(...args) } - for (var i = 0; i < ops; i++) { - writeFileAtomic('test', 'test', function (err) { + for (let i = 0; i < ops; i++) { + writeFileAtomic('test', 'test', err => { if (err) t.fail(err) else t.pass('wrote without error') }) } - setTimeout(function () { - writeFileAtomic('test', 'test', function (err) { + setTimeout(() => { + writeFileAtomic('test', 'test', err => { if (err) t.fail(err) else t.pass('successive writes after delay') }) }, 500) }) -test('allow write to multiple files in parallel, but same file writes are serial', function (t) { - var filesInUse = [] - var ops = 5 - var wasParallel = false - fs.realpath = function (filename) { +test('allow write to multiple files in parallel, but same file writes are serial', t => { + const filesInUse = [] + let ops = 5 + let wasParallel = false + fs.realpath = (filename, ...args) => { filesInUse.push(filename) - var firstOccurence = filesInUse.indexOf(filename) + const firstOccurence = filesInUse.indexOf(filename) t.equal(filesInUse.indexOf(filename, firstOccurence + 1), -1, 'serial writes') // check for another occurence after the first if (filesInUse.length > 1) wasParallel = true // remember that a parallel operation took place - oldRealPath.apply(writeFileAtomic, arguments) + oldRealPath(filename, ...args) } - fs.rename = function (filename) { + fs.rename = (filename, ...args) => { filesInUse.splice(filesInUse.indexOf(filename), 1) - oldRename.apply(writeFileAtomic, arguments) + oldRename(filename, ...args) } t.plan(ops * 2 * 2 + 1) - var opCount = 0 - for (var i = 0; i < ops; i++) { - writeFileAtomic('test', 'test', function (err) { + let opCount = 0 + for (let i = 0; i < ops; i++) { + writeFileAtomic('test', 'test', err => { if (err) t.fail(err, 'wrote without error') else t.pass('wrote without error') }) - writeFileAtomic('test2', 'test', function (err) { + writeFileAtomic('test2', 'test', err => { opCount++ if (opCount === ops) t.true(wasParallel, 'parallel writes') diff --git a/test/integration.js b/test/integration.js index 894b97a..e58b0cc 100644 --- a/test/integration.js +++ b/test/integration.js @@ -1,13 +1,13 @@ 'use strict' -var fs = require('fs') -var path = require('path') -var test = require('tap').test -var mkdirp = require('mkdirp') -var rimraf = require('rimraf') -var requireInject = require('require-inject') - -var workdir = path.join(__dirname, path.basename(__filename, '.js')) -var testfiles = 0 +const fs = require('fs') +const path = require('path') +const { test } = require('tap') +const mkdirp = require('mkdirp') +const rimraf = require('rimraf') +const requireInject = require('require-inject') + +const workdir = path.join(__dirname, path.basename(__filename, '.js')) +let testfiles = 0 function tmpFile () { return path.join(workdir, 'test-' + (++testfiles)) } @@ -22,38 +22,38 @@ function didWriteFileAtomic (t, expected, filename, data, options, callback) { options = null } if (!options) options = {} - var actual = {} - var writeFileAtomic = requireInject('../index.js', { + const actual = {} + const writeFileAtomic = requireInject('../index.js', { 'fs': Object.assign({}, fs, { - chown: function mockChown (filename, uid, gid, cb) { + chown (filename, uid, gid, cb) { actual.uid = uid actual.gid = gid process.nextTick(cb) }, - stat: function mockStat (filename, cb) { - fs.stat(filename, function (err, stats) { + stat (filename, cb) { + fs.stat(filename, (err, stats) => { if (err) return cb(err) cb(null, Object.assign(stats, expected || {})) }) } }) }) - return writeFileAtomic(filename, data, options, function (err) { + return writeFileAtomic(filename, data, options, err => { t.isDeeply(actual, expected, 'ownership is as expected') callback(err) }) } function didWriteFileAtomicSync (t, expected, filename, data, options) { - var actual = {} - var writeFileAtomic = requireInject('../index.js', { + const actual = {} + const writeFileAtomic = requireInject('../index.js', { 'fs': Object.assign({}, fs, { - chownSync: function mockChownSync (filename, uid, gid) { + chownSync (filename, uid, gid) { actual.uid = uid actual.gid = gid }, - statSync: function mockStatSync (filename) { - var stats = fs.statSync(filename) + statSync (filename) { + const stats = fs.statSync(filename) return Object.assign(stats, expected || {}) } }) @@ -69,64 +69,64 @@ function currentUser () { } } -test('setup', function (t) { +test('setup', t => { rimraf.sync(workdir) mkdirp.sync(workdir) t.done() }) -test('writes simple file (async)', function (t) { +test('writes simple file (async)', t => { t.plan(3) - var file = tmpFile() - didWriteFileAtomic(t, {}, file, '42', function (err) { + const file = tmpFile() + didWriteFileAtomic(t, {}, file, '42', err => { t.ifError(err, 'no error') t.is(readFile(file), '42', 'content ok') }) }) -test('writes simple file with encoding (async)', function (t) { +test('writes simple file with encoding (async)', t => { t.plan(3) - var file = tmpFile() - didWriteFileAtomic(t, {}, file, 'foo', 'utf16le', function (err) { + const file = tmpFile() + didWriteFileAtomic(t, {}, file, 'foo', 'utf16le', err => { t.ifError(err, 'no error') t.is(readFile(file), 'f\u0000o\u0000o\u0000', 'content ok') }) }) -test('writes buffers to simple file (async)', function (t) { +test('writes buffers to simple file (async)', t => { t.plan(3) - var file = tmpFile() - didWriteFileAtomic(t, {}, file, Buffer.from('42'), function (err) { + const file = tmpFile() + didWriteFileAtomic(t, {}, file, Buffer.from('42'), err => { t.ifError(err, 'no error') t.is(readFile(file), '42', 'content ok') }) }) -test('writes TypedArray to simple file (async)', function (t) { +test('writes TypedArray to simple file (async)', t => { t.plan(3) - var file = tmpFile() - didWriteFileAtomic(t, {}, file, new Uint8Array([0x34, 0x32]), function (err) { + const file = tmpFile() + didWriteFileAtomic(t, {}, file, new Uint8Array([0x34, 0x32]), err => { t.ifError(err, 'no error') t.is(readFile(file), '42', 'content ok') }) }) -test('writes undefined to simple file (async)', function (t) { +test('writes undefined to simple file (async)', t => { t.plan(3) - var file = tmpFile() - didWriteFileAtomic(t, {}, file, undefined, function (err) { + const file = tmpFile() + didWriteFileAtomic(t, {}, file, undefined, err => { t.ifError(err, 'no error') t.is(readFile(file), '', 'content ok') }) }) -test('writes to symlinks without clobbering (async)', function (t) { +test('writes to symlinks without clobbering (async)', t => { t.plan(5) - var file = tmpFile() - var link = tmpFile() + const file = tmpFile() + const link = tmpFile() fs.writeFileSync(file, '42') fs.symlinkSync(file, link) - didWriteFileAtomic(t, currentUser(), link, '43', function (err) { + didWriteFileAtomic(t, currentUser(), link, '43', err => { t.ifError(err, 'no error') t.is(readFile(file), '43', 'target content ok') t.is(readFile(link), '43', 'link content ok') @@ -134,65 +134,65 @@ test('writes to symlinks without clobbering (async)', function (t) { }) }) -test('runs chown on given file (async)', function (t) { - var file = tmpFile() - didWriteFileAtomic(t, { uid: 42, gid: 43 }, file, '42', { chown: { uid: 42, gid: 43 } }, function (err) { +test('runs chown on given file (async)', t => { + const file = tmpFile() + didWriteFileAtomic(t, { uid: 42, gid: 43 }, file, '42', { chown: { uid: 42, gid: 43 } }, err => { t.ifError(err, 'no error') t.is(readFile(file), '42', 'content ok') t.done() }) }) -test('writes simple file with no chown (async)', function (t) { +test('writes simple file with no chown (async)', t => { t.plan(3) - var file = tmpFile() - didWriteFileAtomic(t, {}, file, '42', { chown: false }, function (err) { + const file = tmpFile() + didWriteFileAtomic(t, {}, file, '42', { chown: false }, err => { t.ifError(err, 'no error') t.is(readFile(file), '42', 'content ok') t.done() }) }) -test('runs chmod on given file (async)', function (t) { +test('runs chmod on given file (async)', t => { t.plan(5) - var file = tmpFile() - didWriteFileAtomic(t, {}, file, '42', { mode: parseInt('741', 8) }, function (err) { + const file = tmpFile() + didWriteFileAtomic(t, {}, file, '42', { mode: parseInt('741', 8) }, err => { t.ifError(err, 'no error') - var stat = fs.statSync(file) + const stat = fs.statSync(file) t.is(stat.mode, parseInt('100741', 8)) - didWriteFileAtomic(t, { uid: 42, gid: 43 }, file, '23', { chown: { uid: 42, gid: 43 } }, function (err) { + didWriteFileAtomic(t, { uid: 42, gid: 43 }, file, '23', { chown: { uid: 42, gid: 43 } }, err => { t.ifError(err, 'no error') }) }) }) -test('run chmod AND chown (async)', function (t) { +test('run chmod AND chown (async)', t => { t.plan(3) - var file = tmpFile() - didWriteFileAtomic(t, { uid: 42, gid: 43 }, file, '42', { mode: parseInt('741', 8), chown: { uid: 42, gid: 43 } }, function (err) { + const file = tmpFile() + didWriteFileAtomic(t, { uid: 42, gid: 43 }, file, '42', { mode: parseInt('741', 8), chown: { uid: 42, gid: 43 } }, err => { t.ifError(err, 'no error') - var stat = fs.statSync(file) + const stat = fs.statSync(file) t.is(stat.mode, parseInt('100741', 8)) }) }) -test('does not change chmod by default (async)', function (t) { +test('does not change chmod by default (async)', t => { t.plan(5) - var file = tmpFile() - didWriteFileAtomic(t, {}, file, '42', { mode: parseInt('741', 8) }, function (err) { + const file = tmpFile() + didWriteFileAtomic(t, {}, file, '42', { mode: parseInt('741', 8) }, err => { t.ifError(err, 'no error') - didWriteFileAtomic(t, currentUser(), file, '43', function (err) { + didWriteFileAtomic(t, currentUser(), file, '43', err => { t.ifError(err, 'no error') - var stat = fs.statSync(file) + const stat = fs.statSync(file) t.is(stat.mode, parseInt('100741', 8)) }) }) }) -test('does not change chown by default (async)', function (t) { +test('does not change chown by default (async)', t => { t.plan(6) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomic(t, { uid: 42, gid: 43 }, file, '42', { chown: { uid: 42, gid: 43 } }, _setModeOnly) function _setModeOnly (err) { @@ -212,45 +212,45 @@ test('does not change chown by default (async)', function (t) { } }) -test('writes simple file (sync)', function (t) { +test('writes simple file (sync)', t => { t.plan(2) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, {}, file, '42') t.is(readFile(file), '42') }) -test('writes simple file with encoding (sync)', function (t) { +test('writes simple file with encoding (sync)', t => { t.plan(2) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, {}, file, 'foo', 'utf16le') t.is(readFile(file), 'f\u0000o\u0000o\u0000') }) -test('writes simple buffer file (sync)', function (t) { +test('writes simple buffer file (sync)', t => { t.plan(2) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, {}, file, Buffer.from('42')) t.is(readFile(file), '42') }) -test('writes simple TypedArray file (sync)', function (t) { +test('writes simple TypedArray file (sync)', t => { t.plan(2) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, {}, file, new Uint8Array([0x34, 0x32])) t.is(readFile(file), '42') }) -test('writes undefined file (sync)', function (t) { +test('writes undefined file (sync)', t => { t.plan(2) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, {}, file, undefined) t.is(readFile(file), '') }) -test('writes to symlinks without clobbering (sync)', function (t) { +test('writes to symlinks without clobbering (sync)', t => { t.plan(4) - var file = tmpFile() - var link = tmpFile() + const file = tmpFile() + const link = tmpFile() fs.writeFileSync(file, '42') fs.symlinkSync(file, link) didWriteFileAtomicSync(t, currentUser(), link, '43') @@ -259,47 +259,47 @@ test('writes to symlinks without clobbering (sync)', function (t) { t.ok(fs.lstatSync(link).isSymbolicLink(), 'link is link') }) -test('runs chown on given file (sync)', function (t) { +test('runs chown on given file (sync)', t => { t.plan(1) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, { uid: 42, gid: 43 }, file, '42', { chown: { uid: 42, gid: 43 } }) }) -test('runs chmod on given file (sync)', function (t) { +test('runs chmod on given file (sync)', t => { t.plan(3) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, {}, file, '42', { mode: parseInt('741', 8) }) - var stat = fs.statSync(file) + const stat = fs.statSync(file) t.is(stat.mode, parseInt('100741', 8)) didWriteFileAtomicSync(t, { uid: 42, gid: 43 }, file, '23', { chown: { uid: 42, gid: 43 } }) }) -test('runs chown and chmod (sync)', function (t) { +test('runs chown and chmod (sync)', t => { t.plan(2) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, { uid: 42, gid: 43 }, file, '42', { mode: parseInt('741', 8), chown: { uid: 42, gid: 43 } }) - var stat = fs.statSync(file) + const stat = fs.statSync(file) t.is(stat.mode, parseInt('100741', 8)) }) -test('does not change chmod by default (sync)', function (t) { +test('does not change chmod by default (sync)', t => { t.plan(3) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, {}, file, '42', { mode: parseInt('741', 8) }) didWriteFileAtomicSync(t, currentUser(), file, '43') - var stat = fs.statSync(file) + const stat = fs.statSync(file) t.is(stat.mode, parseInt('100741', 8)) }) -test('does not change chown by default (sync)', function (t) { +test('does not change chown by default (sync)', t => { t.plan(3) - var file = tmpFile() + const file = tmpFile() didWriteFileAtomicSync(t, { uid: 42, gid: 43 }, file, '42', { chown: { uid: 42, gid: 43 } }) didWriteFileAtomicSync(t, { uid: 42, gid: 43 }, file, '43', { mode: parseInt('741', 8) }) didWriteFileAtomicSync(t, { uid: 42, gid: 43 }, file, '44') }) -test('cleanup', function (t) { +test('cleanup', t => { rimraf.sync(workdir) t.done() })