From f00060325912cdf29c6b66bd0b0b81713c94af75 Mon Sep 17 00:00:00 2001 From: Jared Palmer Date: Sat, 26 Jan 2019 14:31:19 -0500 Subject: [PATCH] Refactor, better logging --- lib/constants.js | 17 +++ lib/createJestConfig.js | 14 ++ lib/createRollupConfig.js | 122 ++++++++++++++++ lib/getInstallCmd.js | 20 +++ lib/index.js | 293 ++++++++++---------------------------- lib/messages.js | 92 ++++++++++++ lib/output.js | 84 +++++++++++ lib/utils.js | 32 +++++ package.json | 3 + yarn.lock | 38 ++++- 10 files changed, 493 insertions(+), 222 deletions(-) create mode 100644 lib/constants.js create mode 100644 lib/createJestConfig.js create mode 100644 lib/createRollupConfig.js create mode 100644 lib/getInstallCmd.js create mode 100644 lib/messages.js create mode 100644 lib/output.js create mode 100644 lib/utils.js diff --git a/lib/constants.js b/lib/constants.js new file mode 100644 index 000000000..d7ebfb5ac --- /dev/null +++ b/lib/constants.js @@ -0,0 +1,17 @@ +const fs = require('fs-extra'); +const path = require('path'); +const { resolveApp } = require('./utils'); + +let paths = {}; + +try { + paths = { + appPackageJson: resolveApp('package.json'), + testsSetup: resolveApp('test/setupTests.ts'), + appRoot: resolveApp('.'), + appSrc: resolveApp('src'), + appDist: resolveApp('dist'), + }; +} catch (e) {} + +exports.paths = paths; diff --git a/lib/createJestConfig.js b/lib/createJestConfig.js new file mode 100644 index 000000000..75953ed69 --- /dev/null +++ b/lib/createJestConfig.js @@ -0,0 +1,14 @@ +const { appPackageJson } = require('./constants'); + +module.exports = function createJestConfig(resolve, rootDir) { + return { + transform: { + '.(ts|tsx)': resolve('./node_modules/ts-jest'), + }, + transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], + collectCoverageFrom: ['src/**/*.{ts,tsx}'], + testMatch: ['/test/**/?(*.)(spec|test).{ts,tsx}'], + rootDir, + }; +}; diff --git a/lib/createRollupConfig.js b/lib/createRollupConfig.js new file mode 100644 index 000000000..682676351 --- /dev/null +++ b/lib/createRollupConfig.js @@ -0,0 +1,122 @@ +const { + safeVariableName, + resolveApp, + removeScope, + external, +} = require('./utils'); + +const { paths, appPackageJson } = require('./constants'); +const { sizeSnapshot } = require('rollup-plugin-size-snapshot'); +const { terser } = require('rollup-plugin-terser'); +const babel = require('rollup-plugin-babel'); +const commonjs = require('rollup-plugin-commonjs'); +const json = require('rollup-plugin-json'); +const replace = require('rollup-plugin-replace'); +const resolve = require('rollup-plugin-node-resolve'); +const sourceMaps = require('rollup-plugin-sourcemaps'); +const typescript = require('rollup-plugin-typescript2'); + +const replacements = [{ original: 'lodash', replacement: 'lodash-es' }]; + +const babelOptions = { + exclude: /node_modules/, + plugins: [ + 'annotate-pure-calls', + 'dev-expression', + ['transform-rename-import', { replacements }], + ], +}; + +module.exports = function createRollupConfig(format, env, opts) { + return { + // Tell Rollup the entry point to the package + input: resolveApp(opts.input), + // Tell Rollup which packages to ignore + external, + // Establish Rollup output + output: { + // Set filenames of the consumer's package + file: `${paths.appDist}/${safeVariableName( + opts.name + )}.${format}.${env}.js`, + // Pass through the file format + format, + // Do not let Rollup call Object.freeze() on namespace import objects + // (i.e. import * as namespaceImportObject from...) that are accessed dynamically. + freeze: false, + // Do not let Rollup add a `__esModule: true` property when generating exports for non-ESM formats. + esModule: false, + // Rollup has treeshaking by default, but we can optimize it further... + treeshake: { + // We assume reading a property of an object never has side-effects. + // This means tsdx WILL remove getters and setters on objects. + // + // @example + // + // const foo = { + // get bar() { + // console.log('effect'); + // return 'bar'; + // } + // } + // + // const result = foo.bar; + // const illegalAccess = foo.quux.tooDeep; + // + // Punchline....Don't use getters and setters + propertyReadSideEffects: false, + }, + name: opts.name || safeVariableName(opts.name), + sourcemap: true, + globals: { react: 'React', 'react-native': 'ReactNative' }, + exports: 'named', + }, + plugins: [ + resolve({ + module: true, + jsnext: true, + browser: opts.target !== 'node', + }), + env === 'umd' && + commonjs({ + // use a regex to make sure to include eventual hoisted packages + include: /\/node_modules\//, + }), + json(), + typescript({ + typescript: require('typescript'), + cacheRoot: `./.rts2_cache_${format}`, + tsconfigDefaults: { + compilerOptions: { + sourceMap: true, + declaration: true, + jsx: 'react', + }, + }, + tsconfigOverride: { + compilerOptions: { + target: 'esnext', + }, + }, + }), + babel(babelOptions), + replace({ + 'process.env.NODE_ENV': JSON.stringify(env), + }), + sourceMaps(), + sizeSnapshot(), + env === 'production' && + terser({ + sourcemap: true, + output: { comments: false }, + compress: { + keep_infinity: true, + pure_getters: true, + }, + ecma: 5, + toplevel: format === 'es' || format === 'cjs', + warnings: true, + }), + ], + }; +}; diff --git a/lib/getInstallCmd.js b/lib/getInstallCmd.js new file mode 100644 index 000000000..625652274 --- /dev/null +++ b/lib/getInstallCmd.js @@ -0,0 +1,20 @@ +'use strict'; + +const execa = require('execa'); + +let cmd; + +module.exports = function getInstallCmd() { + if (cmd) { + return cmd; + } + + try { + execa.sync('yarnpkg', ['--version']); + cmd = 'yarn'; + } catch (e) { + cmd = 'npm'; + } + + return cmd; +}; diff --git a/lib/index.js b/lib/index.js index 794ab4854..949165f2d 100755 --- a/lib/index.js +++ b/lib/index.js @@ -2,169 +2,40 @@ const sade = require('sade'); const { rollup, watch } = require('rollup'); -const { sizeSnapshot } = require('rollup-plugin-size-snapshot'); -const { terser } = require('rollup-plugin-terser'); const asyncro = require('asyncro'); -const babel = require('rollup-plugin-babel'); -const camelCase = require('camelcase'); -const commonjs = require('rollup-plugin-commonjs'); +const chalk = require('chalk'); const fs = require('fs-extra'); const jest = require('jest'); -const json = require('rollup-plugin-json'); const logError = require('./logError'); const path = require('path'); const mkdirp = require('mkdirp'); -const replace = require('rollup-plugin-replace'); -const resolve = require('rollup-plugin-node-resolve'); -const sourceMaps = require('rollup-plugin-sourcemaps'); -const typescript = require('rollup-plugin-typescript2'); const execa = require('execa'); - +const ora = require('ora'); +const { paths } = require('./constants'); +const messages = require('./messages'); +const createRollupConfig = require('./createRollupConfig'); +const createJestConfig = require('./createJestConfig'); +const { safeVariableName, resolveApp, safePackageName } = require('./utils'); +const output = require('./output'); const prog = sade('tsdx'); -// Make sure any symlinks in the project folder are resolved: -// https://github.com/facebookincubator/create-react-app/issues/637 -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = relativePath => path.resolve(appDirectory, relativePath); - -// Remove the package name scope if it exists -const removeScope = name => name.replace(/^@.*\//, ''); -// UMD-safe package name -const safeVariableName = name => - camelCase( - removeScope(name) - .toLowerCase() - .replace(/((^[^a-zA-Z]+)|[^\w.-])|([^a-zA-Z0-9]+$)/g, '') - ); let appPackageJson; -let paths; try { appPackageJson = fs.readJSONSync(resolveApp('package.json')); - paths = { - appPackageJson: resolveApp('package.json'), - testsSetup: resolveApp('test/setupTests.ts'), - appRoot: resolveApp('.'), - appSrc: resolveApp('src'), - appEntry: resolveApp(appPackageJson.source), - appDist: resolveApp('dist'), - }; } catch (e) {} -const external = id => !id.startsWith('.') && !id.startsWith('/'); - -const replacements = [{ original: 'lodash', replacement: 'lodash-es' }]; - -const babelOptions = { - exclude: /node_modules/, - plugins: [ - 'annotate-pure-calls', - 'dev-expression', - ['transform-rename-import', { replacements }], - ], +const createBuildConfigs = opts => { + opts.name = opts.name || appPackageJson.name; + opts.input = appPackageJson.source; + return [ + createRollupConfig('cjs', 'development', opts), + createRollupConfig('cjs', 'production', opts), + createRollupConfig('es', 'production', opts), + createRollupConfig('umd', 'development', opts), + createRollupConfig('umd', 'production', opts), + ]; }; -const getBuildConfigurations = opts => [ - getConfig('cjs', 'development', opts), - getConfig('cjs', 'production', opts), - getConfig('es', 'production', opts), - getConfig('umd', 'development', opts), - getConfig('umd', 'production', opts), -]; - -function getConfig(format, env, opts) { - return { - // Tell Rollup the entry point to the package - input: paths.appEntry, - // Tell Rollup which packages to ignore - external, - // Establish Rollup output - output: { - // Set filenames of the consumer's package - file: `${paths.appDist}/${safeVariableName( - appPackageJson.name - )}.${format}.${env}.js`, - // Pass through the file format - format, - // Do not let Rollup call Object.freeze() on namespace import objects - // (i.e. import * as namespaceImportObject from...) that are accessed dynamically. - freeze: false, - // Do not let Rollup add a `__esModule: true` property when generating exports for non-ESM formats. - esModule: false, - // Rollup has treeshaking by default, but we can optimize it further... - treeshake: { - // We assume reading a property of an object never has side-effects. - // This means tsdx WILL remove getters and setters on objects. - // - // @example - // - // const foo = { - // get bar() { - // console.log('effect'); - // return 'bar'; - // } - // } - // - // const result = foo.bar; - // const illegalAccess = foo.quux.tooDeep; - // - // Punchline....Don't use getters and setters - propertyReadSideEffects: false, - }, - name: opts.name || safeVariableName(appPackageJson.name), - sourcemap: true, - globals: { react: 'React', 'react-native': 'ReactNative' }, - exports: 'named', - }, - plugins: [ - resolve({ - module: true, - jsnext: true, - browser: opts.target !== 'node', - }), - env === 'umd' && - commonjs({ - // use a regex to make sure to include eventual hoisted packages - include: /\/node_modules\//, - }), - json(), - typescript({ - typescript: require('typescript'), - cacheRoot: `./.rts2_cache_${format}`, - tsconfigDefaults: { - compilerOptions: { - sourceMap: true, - declaration: true, - jsx: 'react', - }, - }, - tsconfigOverride: { - compilerOptions: { - target: 'esnext', - }, - }, - }), - babel(babelOptions), - replace({ - 'process.env.NODE_ENV': JSON.stringify(env), - }), - sourceMaps(), - sizeSnapshot(), - env === 'production' && - terser({ - sourcemap: true, - output: { comments: false }, - compress: { - keep_infinity: true, - pure_getters: true, - }, - ecma: 5, - toplevel: format === 'es' || format === 'cjs', - warnings: true, - }), - ], - }; -} - async function moveTypes() { try { // Move the typescript types to the base of the ./dist folder @@ -175,21 +46,14 @@ async function moveTypes() { } catch (e) {} } -// Add shared flags to watch and build commands imperatively -function addRollupCliFlagsToProg(cli) { - cli - .option('--target', 'Specify your target environment', 'web') - .example('tsdx watch --target node') - .option('--name', 'Specify name exposed in UMD builds'); -} - prog .command('create ') .describe('Create a new package with TSDX') .action(async pkg => { + const bootSpinner = ora(`Creating ${chalk.bold.green(pkg)}...`).start(); + try { - console.log('Bootstrapping new project...'); - const projectPath = process.cwd() + '/' + pkg; + const projectPath = fs.realpathSync(process.cwd()) + '/' + pkg; // copy the template await fs.copy(path.resolve(__dirname, './template'), projectPath, { overwrite: true, @@ -201,7 +65,7 @@ prog ); // Install deps process.chdir(projectPath); - const safeName = safeVariableName(pkg); + const safeName = safePackageName(pkg); const pkgJson = { name: safeName, version: '0.1.0', @@ -217,63 +81,64 @@ prog }, }; await fs.outputJSON(path.resolve(projectPath, 'package.json'), pkgJson); + bootSpinner.succeed(`Created ${chalk.bold.green(pkg)}`); + messages.start(pkg); + } catch (error) { + bootSpinner.fail(`Failed to create ${chalk.bold.red(pkg)}`); + logError(error); + process.exit(1); + } + const deps = ['@types/jest', 'tsdx', 'typescript']; - console.log('Installing dependencies...'); - - await execa(`yarn`, [ - 'add', - '@types/jest', - 'tsdx', - 'typescript', - '--dev', - ]); - console.log(` -Success!! TSDX just bootstrapped a brand new project for you. To get started, run: - - cd ${pkg} - yarn start - - `); + const installSpinner = ora(messages.installing(deps)).start(); + try { + await execa(`yarn`, ['add', ...deps, '--dev']); + installSpinner.succeed('Installed dependecines'); + console.log(messages.start(pkg)); } catch (error) { + installSpinner.fail('Failed to install dependencies'); logError(error); + process.exit(1); } }); -prog.command('watch').describe('Rebuilds on any change'); - -addRollupCliFlagsToProg(prog); - -prog.action(async opts => { - await watch( - getBuildConfigurations(opts).map(inputOptions => ({ - watch: { - silent: true, - include: 'src/**', - exclude: 'node_modules/**', - }, - ...inputOptions, - })) - ).on('event', async event => { - if (event.code === 'ERROR') { - logError(event.error); - } - if (event.code === 'FATAL') { - logError(event.error); - } - if (event.code === 'END') { - try { - await moveTypes(); - } catch (_error) {} - } +prog + .command('watch') + .describe('Rebuilds on any change') + .option('--target', 'Specify your target environment', 'web') + .example('tsdx watch --target node') + .option('--name', 'Specify name exposed in UMD builds') + .action(async opts => { + await watch( + createBuildConfigs(opts).map(inputOptions => ({ + watch: { + silent: true, + include: 'src/**', + exclude: 'node_modules/**', + }, + ...inputOptions, + })) + ).on('event', async event => { + if (event.code === 'ERROR') { + logError(event.error); + } + if (event.code === 'FATAL') { + logError(event.error); + } + if (event.code === 'END') { + try { + await moveTypes(); + } catch (_error) {} + } + }); }); -}); prog .command('build') .describe('Build your project once and exit') .action(async opts => { try { - await asyncro.map(getBuildConfigurations(opts), async inputOptions => { + await asyncro.map(createBuildConfigs(opts), async inputOptions => { let bundle = await rollup(inputOptions); await bundle.write(inputOptions.output); }); @@ -313,29 +178,15 @@ prog ? '/src/setupTests.ts' : undefined; - const createJestConfig = (resolve, rootDir) => { - const overrides = appPackageJson.jest; - return { - transform: { - '.(ts|tsx)': resolve('./node_modules/ts-jest'), - }, - transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$'], - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], - collectCoverageFrom: ['src/**/*.{ts,tsx}'], - testMatch: ['/test/**/?(*.)(spec|test).{ts,tsx}'], - ...overrides, - rootDir, - }; - }; - argv.push( '--config', - JSON.stringify( - createJestConfig( + JSON.stringify({ + ...createJestConfig( relativePath => path.resolve(__dirname, '..', relativePath), paths.appRoot - ) - ) + ), + ...appPackageJson.jest, + }) ); const [_skipTheWordTest, ...argsToPassToJestCli] = argv; diff --git a/lib/messages.js b/lib/messages.js new file mode 100644 index 000000000..d22489b4e --- /dev/null +++ b/lib/messages.js @@ -0,0 +1,92 @@ +'use strict'; + +const chalk = require('chalk'); +const getInstallCmd = require('./getInstallCmd'); +const output = require('./output'); + +const program = { + name: 'tsdx', +}; + +exports.help = function() { + return ` + Only ${chalk.green('')} is required. + If you have any problems, do not hesitate to file an issue: + ${chalk.cyan('https://github.com/jaredpalmer/tsdx/issues/new')} + `; +}; + +exports.missingProjectName = function() { + return ` +Please specify the project directory: + ${chalk.cyan(program.name)} ${chalk.green('')} +For example: + ${chalk.cyan(program.name)} ${chalk.green('my-tsdx-lib')} +Run ${chalk.cyan(`${program.name} --help`)} to see all options. +`; +}; + +exports.alreadyExists = function(projectName) { + return ` +Uh oh! Looks like there's already a directory called ${chalk.red( + projectName + )}. Please try a different name or delete that folder.`; +}; + +exports.installing = function(packages) { + const pkgText = packages + .map(function(pkg) { + return ` ${chalk.cyan(chalk.bold(pkg))}`; + }) + .join('\n'); + + return `Installing npm modules: +${pkgText} +`; +}; + +exports.installError = function(packages) { + const pkgText = packages + .map(function(pkg) { + return `${chalk.cyan(chalk.bold(pkg))}`; + }) + .join(', '); + + output.error(`Failed to install ${pkgText}, try again.`); +}; + +exports.copying = function(projectName) { + return ` +Creating ${chalk.bold(chalk.green(projectName))}... +`; +}; + +exports.start = function(projectName) { + const cmd = getInstallCmd(); + + const commands = { + install: cmd === 'npm' ? 'npm install' : 'yarn install', + build: cmd === 'npm' ? 'npm run build' : 'yarn build', + start: cmd === 'npm' ? 'npm run start' : 'yarn start', + test: cmd === 'npm' ? 'npm test' : 'yarn test', + }; + + return ` + ${chalk.green('Awesome!')} You're now ready to start coding. + + I already ran ${output.cmd(commands.install)} for you, so your next steps are: + ${output.cmd(`cd ${projectName}`)} + + To start developing (rebuilds on changes): + ${output.cmd(commands.start)} + + To build for production: + ${output.cmd(commands.build)} + + To test your library with Jest: + ${output.cmd(commands.test)} + + Questions? Feedback? Please let me know! + ${chalk.green('https://github.com/jaredpalmer/tsdx/issues')} +`; +}; diff --git a/lib/output.js b/lib/output.js new file mode 100644 index 000000000..035bc72f9 --- /dev/null +++ b/lib/output.js @@ -0,0 +1,84 @@ +'use strict'; + +const { eraseLine } = require('ansi-escapes'); +const chalk = require('chalk'); +const ora = require('ora'); +const ms = require('ms'); + +exports.info = function(msg) { + console.log(`${chalk.gray('>')} ${msg}`); +}; + +exports.error = function(msg) { + if (msg instanceof Error) { + msg = msg.message; + } + + console.error(`${chalk.red('> Error!')} ${msg}`); +}; + +exports.success = function(msg) { + console.log(`${chalk.green('> Success!')} ${msg}`); +}; + +exports.time = function() { + const start = new Date(); + return chalk.gray(`[${ms(new Date() - start)}]`); +}; + +exports.wait = function(msg) { + const spinner = ora(chalk.green(msg)); + spinner.color = 'blue'; + spinner.start(); + + return function() { + spinner.stop(); + process.stdout.write(eraseLine); + }; +}; + +exports.prompt = function(opts) { + return new Promise(function(resolve, reject) { + opts.forEach(function(val, i) { + const text = val[1]; + console.log(`${chalk.gray('>')} [${chalk.bold(i + 1)}] ${text}`); + }); + + const ondata = v => { + const s = v.toString(); + + function cleanup() { + process.stdin.setRawMode(false); + process.stdin.removeListener('data', ondata); + } + + if (s === '\u0003') { + cleanup(); + reject(new Error('Aborted')); + return; + } + + const n = Number(s); + if (opts[n - 1]) { + cleanup(); + resolve(opts[n - 1][0]); + } + }; + + process.stdin.setRawMode(true); + process.stdin.resume(); + process.stdin.on('data', ondata); + }); +}; + +exports.cmd = function(cmd) { + return chalk.bold(chalk.cyan(cmd)); +}; + +exports.code = function(cmd) { + return `${chalk.gray('`')}${chalk.bold(cmd)}${chalk.gray('`')}`; +}; + +exports.param = function(param) { + return chalk.bold(`${chalk.gray('{')}${chalk.bold(param)}${chalk.gray('}')}`); +}; diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 000000000..d2b8656e3 --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,32 @@ +const fs = require('fs-extra'); +const path = require('path'); +const camelCase = require('camelcase'); +// Remove the package name scope if it exists +const removeScope = name => name.replace(/^@.*\//, ''); + +// UMD-safe package name +const safeVariableName = name => + camelCase( + removeScope(name) + .toLowerCase() + .replace(/((^[^a-zA-Z]+)|[^\w.-])|([^a-zA-Z0-9]+$)/g, '') + ); + +const safePackageName = name => + name.toLowerCase().replace(/((^[^a-zA-Z]+)|[^\w.-])|([^a-zA-Z0-9]+$)/g, ''); + +const external = id => !id.startsWith('.') && !id.startsWith('/'); + +// Make sure any symlinks in the project folder are resolved: +// https://github.com/facebookincubator/create-react-app/issues/637 +const appDirectory = fs.realpathSync(process.cwd()); +const resolveApp = function(relativePath) { + return path.resolve(appDirectory, relativePath); +}; + +module.exports = { + safePackageName, + safeVariableName, + resolveApp, + removeScope, +}; diff --git a/package.json b/package.json index 28a76ba82..811b06db6 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ ], "dependencies": { "@babel/core": "^7.2.2", + "ansi-escapes": "^3.1.0", "asyncro": "^3.0.0", "babel-plugin-annotate-pure-calls": "^0.4.0", "babel-plugin-dev-expression": "^0.2.1", @@ -21,6 +22,8 @@ "fs-extra": "^7.0.1", "jest": "23.6.0", "mkdirp": "^0.5.1", + "ms": "^2.1.1", + "ora": "^3.0.0", "rollup": "^0.66.4", "rollup-plugin-babel": "^4.0.3", "rollup-plugin-commonjs": "^9.1.8", diff --git a/yarn.lock b/yarn.lock index 778761036..2a45381b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -370,7 +370,7 @@ ajv@^6.1.0, ajv@^6.5.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-escapes@^3.0.0: +ansi-escapes@^3.0.0, ansi-escapes@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== @@ -1131,6 +1131,11 @@ cli-cursor@^2.0.0, cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" +cli-spinners@^1.1.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" + integrity sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg== + cli-truncate@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" @@ -1148,6 +1153,11 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -1462,6 +1472,13 @@ default-require-extensions@^1.0.0: dependencies: strip-bom "^2.0.0" +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + define-properties@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -4068,6 +4085,18 @@ optionator@^0.8.1: type-check "~0.3.2" wordwrap "~1.0.0" +ora@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-3.0.0.tgz#8179e3525b9aafd99242d63cc206fd64732741d0" + integrity sha512-LBS97LFe2RV6GJmXBi6OKcETKyklHNMV0xw7BtsVn2MlsgsydyZetSCbCANr+PFLmDyv4KV88nn0eCKza665Mg== + dependencies: + chalk "^2.3.1" + cli-cursor "^2.1.0" + cli-spinners "^1.1.0" + log-symbols "^2.2.0" + strip-ansi "^4.0.0" + wcwidth "^1.0.1" + os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" @@ -5762,6 +5791,13 @@ watchpack@^1.5.0: graceful-fs "^4.1.2" neo-async "^2.5.0" +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"