diff --git a/README.md b/README.md index 816396eb9..3586c8e6d 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,9 @@ if (!condition) { } ``` -Recommended for use with smaller https://github.com/alexreardon/tiny-invariant. +Note: TSDX doesn't supply an `invariant` function for you, you need to import one yourself. We recommend https://github.com/alexreardon/tiny-invariant. + +To extract and minify error codes in production into a static `codes.json` file, pass an `extractErrors` flag with a URL where you will decode the error code. Example: `tsdx build --extractErrors=https://your-url.com/?invariant=` ##### `warning` @@ -214,7 +216,7 @@ if ('production' !== process.env.NODE_ENV) { } ``` -Recommended for use with https://github.com/alexreardon/tiny-warning. +Note: TSDX doesn't supply a `warning` function for you, you need to import one yourself. We recommend https://github.com/alexreardon/tiny-warning. ### Using lodash @@ -304,18 +306,20 @@ Usage $ tsdx build [options] Options - -i, --entry Entry module(s) - --target Specify your target environment (default web) - --name Specify name exposed in UMD builds - --format Specify module format(s) (default cjs,esm) - --tsconfig Specify your custom tsconfig path (default /tsconfig.json) - -h, --help Displays this message + -i, --entry Entry module(s) + --target Specify your target environment (default web) + --name Specify name exposed in UMD builds + --format Specify module format(s) (default cjs,esm) + --extractErrors Specify url for extracting error codes + --tsconfig Specify your custom tsconfig path (default /tsconfig.json) + -h, --help Displays this message Examples $ tsdx build --entry src/foo.tsx $ tsdx build --target node $ tsdx build --name Foo $ tsdx build --format cjs,esm,umd + $ tsdx build --extractErrors=https://reactjs.org/docs/error-decoder.html?invariant= $ tsdx build --tsconfig ./tsconfig.foo.json ``` @@ -323,6 +327,12 @@ Examples This runs Jest v24.x in watch mode. See [https://jestjs.io](https://jestjs.io) for options. If you are using the React template, jest uses the flag `--env=jsdom` by default. +## Hosting extracted Errors + +After running `--extractErrors`, you will have a `codes.json` file with all your extracted error codes. You will need to host the decoder somewhere (with the URL that you passed in to `--extractErrors`). + +_Simple guide to host error codes to be completed_ + ## Author - [Jared Palmer](https://twitter.com/jaredpalmer) diff --git a/package.json b/package.json index 1969f505a..39317148a 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ ], "dependencies": { "@babel/core": "^7.4.4", + "@babel/helper-module-imports": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.4.4", "@babel/polyfill": "^7.4.4", "@babel/preset-env": "^7.4.4", @@ -40,6 +41,8 @@ "babel-plugin-dev-expression": "^0.2.1", "babel-plugin-transform-async-to-promises": "^0.8.11", "babel-plugin-transform-rename-import": "^2.3.0", + "babel-traverse": "^6.26.0", + "babylon": "^6.18.0", "camelcase": "^5.0.0", "chalk": "^2.4.2", "cross-env": "5.2.0", @@ -51,6 +54,7 @@ "jpjs": "^1.2.1", "mkdirp": "^0.5.1", "ora": "^3.4.0", + "pascal-case": "^2.0.1", "progress-estimator": "^0.2.2", "rollup": "^1.12.0", "rollup-plugin-babel": "^4.3.2", @@ -71,7 +75,7 @@ "@types/ansi-escapes": "^4.0.0", "@types/camelcase": "^5.2.0", "@types/execa": "^0.9.0", - "@types/fs-extra": "^7.0.0", + "@types/fs-extra": "^8.0.0", "@types/jest": "^24.0.15", "@types/mkdirp": "^0.5.2", "@types/ms": "^0.7.30", diff --git a/src/constants.ts b/src/constants.ts index 5dc28ca26..f47db0a60 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -5,5 +5,6 @@ export const paths = { testsSetup: resolveApp('test/setupTests.ts'), appRoot: resolveApp('.'), appSrc: resolveApp('src'), + appErrorsJson: resolveApp('./codes.json'), appDist: resolveApp('dist'), }; diff --git a/src/createRollupConfig.ts b/src/createRollupConfig.ts index df2dd7ee0..f7fe58ff5 100644 --- a/src/createRollupConfig.ts +++ b/src/createRollupConfig.ts @@ -9,14 +9,25 @@ import replace from 'rollup-plugin-replace'; import resolve from 'rollup-plugin-node-resolve'; import sourceMaps from 'rollup-plugin-sourcemaps'; import typescript from 'rollup-plugin-typescript2'; -import shebangPlugin from '@jaredpalmer/rollup-plugin-preserve-shebang'; +import { extractErrors } from './errors/extractErrors'; const replacements = [{ original: 'lodash', replacement: 'lodash-es' }]; -const babelOptions = ( - format: 'cjs' | 'esm' | 'umd', - target: 'node' | 'browser' -) => ({ +const errorCodeOpts = { + errorMapFilePath: paths.appRoot + '/errors/codes.json', +}; + +interface TsdxOptions { + input: string; + name: string; + target: 'node' | 'browser'; + env: 'development' | 'production'; + tsconfig?: string; + extractErrors?: string; + minify?: boolean; +} + +const babelOptions = (format: 'cjs' | 'esm' | 'umd', opts: TsdxOptions) => ({ exclude: 'node_modules/**', extensions: [...DEFAULT_EXTENSIONS, 'ts', 'tsx'], passPerPreset: true, // @see https://babeljs.io/docs/en/options#passperpreset @@ -26,7 +37,7 @@ const babelOptions = ( { loose: true, modules: false, - targets: target === 'node' ? { node: '8' } : undefined, + targets: opts.target === 'node' ? { node: '8' } : undefined, exclude: ['transform-async-to-generator'], }, ], @@ -46,22 +57,22 @@ const babelOptions = ( require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }, ], + opts.extractErrors && require('./errors/transformErrorMessages'), ].filter(Boolean), }); // shebang cache map thing because the transform only gets run once let shebang: any = {}; + export function createRollupConfig( format: 'cjs' | 'umd' | 'esm', - opts: { - env?: 'development' | 'production'; - minify?: boolean; - input: string; - name: string; - target: 'node' | 'browser'; - tsconfig?: string; - } + opts: TsdxOptions ) { + const findAndRecordErrorCodes = extractErrors({ + ...errorCodeOpts, + ...opts, + }); + const shouldMinify = opts.minify !== undefined ? opts.minify : opts.env === 'production'; @@ -122,6 +133,12 @@ export function createRollupConfig( exports: 'named', }, plugins: [ + !!opts.extractErrors && { + transform(source: any) { + findAndRecordErrorCodes(source); + return source; + }, + }, resolve({ mainFields: [ 'module', @@ -172,7 +189,7 @@ export function createRollupConfig( }, }, }), - babel(babelOptions(format, opts.target)), + babel(babelOptions(format, opts)), opts.env !== undefined && replace({ 'process.env.NODE_ENV': JSON.stringify(opts.env), diff --git a/src/env.d.ts b/src/env.d.ts index 53a2ed21f..960c064c6 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -18,3 +18,6 @@ declare module 'rollup-plugin-babel'; declare module 'rollup-plugin-size-snapshot'; declare module 'rollup-plugin-terser'; declare module 'camelcase'; +declare module 'babel-traverse'; +declare module 'babylon'; +declare module '@babel/helper-module-imports'; diff --git a/src/errors/evalToString.ts b/src/errors/evalToString.ts new file mode 100644 index 000000000..da9e68192 --- /dev/null +++ b/src/errors/evalToString.ts @@ -0,0 +1,13 @@ +export function evalToString(ast: any): string { + switch (ast.type) { + case 'StringLiteral': + return ast.value; + case 'BinaryExpression': // `+` + if (ast.operator !== '+') { + throw new Error('Unsupported binary operator ' + ast.operator); + } + return evalToString(ast.left) + evalToString(ast.right); + default: + throw new Error('Unsupported type ' + ast.type); + } +} diff --git a/src/errors/extractErrors.ts b/src/errors/extractErrors.ts new file mode 100644 index 000000000..9dab430d6 --- /dev/null +++ b/src/errors/extractErrors.ts @@ -0,0 +1,156 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +import fs from 'fs-extra'; +import * as babylon from 'babylon'; +import traverse from 'babel-traverse'; +import { invertObject } from './invertObject'; +import { evalToString } from './evalToString'; +import { paths } from '../constants'; +import { safeVariableName } from '../utils'; +import pascalCase from 'pascal-case'; + +const babylonOptions = { + sourceType: 'module', + // As a parser, babylon has its own options and we can't directly + // import/require a babel preset. It should be kept **the same** as + // the `babel-plugin-syntax-*` ones specified in + // https://github.com/facebook/fbjs/blob/master/packages/babel-preset-fbjs/configure.js + plugins: [ + 'classProperties', + 'flow', + 'jsx', + 'trailingFunctionCommas', + 'objectRestSpread', + ], +}; + +export function extractErrors(opts: any) { + if (!opts || !('errorMapFilePath' in opts)) { + throw new Error( + 'Missing options. Ensure you pass an object with `errorMapFilePath`.' + ); + } + + if (!opts.name || !('name' in opts)) { + throw new Error('Missing options. Ensure you pass --name flag to tsdx'); + } + + if (typeof opts.extractErrors === 'boolean') { + throw new Error( + 'No url passed to extractErrors flag.' + + 'Ensure you pass a url, eg. `--extractErrors=https://reactjs.org/docs/error-decoder.html?invariant=`.' + ); + } + + const errorMapFilePath = opts.errorMapFilePath; + let existingErrorMap: any; + try { + // Using `fs.readFileSync` instead of `require` here, because `require()` + // calls are cached, and the cache map is not properly invalidated after + // file changes. + existingErrorMap = JSON.parse(fs.readFileSync(errorMapFilePath, 'utf8')); + } catch (e) { + existingErrorMap = {}; + } + + const allErrorIDs = Object.keys(existingErrorMap); + let currentID: any; + + if (allErrorIDs.length === 0) { + // Map is empty + currentID = 0; + } else { + currentID = Math.max.apply(null, allErrorIDs as any) + 1; + } + + // Here we invert the map object in memory for faster error code lookup + existingErrorMap = invertObject(existingErrorMap); + + function transform(source: string) { + const ast = babylon.parse(source, babylonOptions); + + traverse(ast, { + CallExpression: { + exit(astPath: any) { + if (astPath.get('callee').isIdentifier({ name: 'invariant' })) { + const node = astPath.node; + + // error messages can be concatenated (`+`) at runtime, so here's a + // trivial partial evaluator that interprets the literal value + const errorMsgLiteral = evalToString(node.arguments[1]); + addToErrorMap(errorMsgLiteral); + } + }, + }, + }); + } + + function addToErrorMap(errorMsgLiteral: any) { + if (existingErrorMap.hasOwnProperty(errorMsgLiteral)) { + return; + } + existingErrorMap[errorMsgLiteral] = '' + currentID++; + } + + function flush(cb?: any) { + const prettyName = pascalCase(safeVariableName(opts.name)); + // Output messages to ./codes.json + fs.writeFileSync( + errorMapFilePath, + JSON.stringify(invertObject(existingErrorMap), null, 2) + '\n', + 'utf-8' + ); + + // Ensure that the ./src/errors directory exists or create it + fs.ensureDirSync(paths.appRoot + '/errors'); + + // Write the error files, unless they already exist + fs.writeFileSync( + paths.appRoot + '/errors/ErrorDev.js', + ` +function ErrorDev(message) { + const error = new Error(message); + error.name = 'Invariant Violation'; + return error; +} + +export default ErrorDev; + `, + 'utf-8' + ); + + fs.writeFileSync( + paths.appRoot + '/errors/ErrorProd.js', + `// Do not require this module directly! Use a normal error constructor with +// template literal strings. The messages will be converted to ErrorProd during +// build, and in production they will be minified. + +function ErrorProd(code) { + let url = '${opts.extractErrors}' + code; + for (let i = 1; i < arguments.length; i++) { + url += '&args[]=' + encodeURIComponent(arguments[i]); + } + return new Error( + \`Minified ${prettyName} error #\$\{code\}; visit \$\{url\} for the full message or \` + + 'use the non-minified dev environment for full errors and additional \' + + 'helpful warnings. ' + ); +} + +export default ErrorProd; +`, + 'utf-8' + ); + } + + return function extractErrors(source: any) { + transform(source); + flush(); + }; +} diff --git a/src/errors/invertObject.ts b/src/errors/invertObject.ts new file mode 100644 index 000000000..5a2f80ef5 --- /dev/null +++ b/src/errors/invertObject.ts @@ -0,0 +1,24 @@ +/** + * turns + * { 'MUCH ERROR': '0', 'SUCH WRONG': '1' } + * into + * { 0: 'MUCH ERROR', 1: 'SUCH WRONG' } + */ + +type Dict = { [key: string]: any }; + +export function invertObject( + targetObj: Dict /* : ErrorMap */ +) /* : ErrorMap */ { + const result: Dict = {}; + const mapKeys = Object.keys(targetObj); + + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const originalKey of mapKeys) { + const originalVal = targetObj[originalKey]; + + result[originalVal] = originalKey; + } + + return result; +} diff --git a/src/errors/transformErrorMessages.ts b/src/errors/transformErrorMessages.ts new file mode 100644 index 000000000..193185823 --- /dev/null +++ b/src/errors/transformErrorMessages.ts @@ -0,0 +1,151 @@ +import fs from 'fs'; +import { invertObject } from './invertObject'; +import { evalToString } from './evalToString'; +import { addDefault } from '@babel/helper-module-imports'; +import { paths } from '../constants'; + +export default function transformErrorMessages(babel: any) { + const t = babel.types; + + const DEV_EXPRESSION = t.identifier('__DEV__'); + + return { + visitor: { + CallExpression(path: any, file: any) { + const node = path.node; + const noMinify = file.opts.noMinify; + if (path.get('callee').isIdentifier({ name: 'invariant' })) { + // Turns this code: + // + // invariant(condition, 'A %s message that contains %s', adj, noun); + // + // into this: + // + // if (!condition) { + // if (__DEV__) { + // throw ReactError(`A ${adj} message that contains ${noun}`); + // } else { + // throw ReactErrorProd(ERR_CODE, adj, noun); + // } + // } + // + // where ERR_CODE is an error code: a unique identifier (a number + // string) that references a verbose error message. The mapping is + // stored in `paths.appRoot + "/codes.json"`. + const condition = node.arguments[0]; + const errorMsgLiteral = evalToString(node.arguments[1]); + const errorMsgExpressions = Array.from(node.arguments.slice(2)); + const errorMsgQuasis = errorMsgLiteral + .split('%s') + .map((raw: any) => + t.templateElement({ raw, cooked: String.raw({ raw } as any) }) + ); + + // Import ReactError + const reactErrorIdentfier = addDefault( + path, + paths.appRoot + '/errors/ErrorDev.js', + { + nameHint: 'InvariantError', + } + ); + + // Outputs: + // throw ReactError(`A ${adj} message that contains ${noun}`); + const devThrow = t.throwStatement( + t.callExpression(reactErrorIdentfier, [ + t.templateLiteral(errorMsgQuasis, errorMsgExpressions), + ]) + ); + + if (noMinify) { + // Error minification is disabled for this build. + // + // Outputs: + // if (!condition) { + // throw ReactError(`A ${adj} message that contains ${noun}`); + // } + path.replaceWith( + t.ifStatement( + t.unaryExpression('!', condition), + t.blockStatement([devThrow]) + ) + ); + return; + } + + // Avoid caching because we write it as we go. + const existingErrorMap = JSON.parse( + fs.readFileSync(paths.appErrorsJson, 'utf-8') + ); + const errorMap = invertObject(existingErrorMap); + + let prodErrorId = errorMap[errorMsgLiteral]; + + if (prodErrorId === undefined) { + // There is no error code for this message. Add an inline comment + // that flags this as an unminified error. This allows the build + // to proceed, while also allowing a post-build linter to detect it. + // + // Outputs: + // /* FIXME (minify-errors-in-prod): Unminified error message in production build! */ + // if (!condition) { + // throw ReactError(`A ${adj} message that contains ${noun}`); + // } + path.replaceWith( + t.ifStatement( + t.unaryExpression('!', condition), + t.blockStatement([devThrow]) + ) + ); + path.addComment( + 'leading', + 'FIXME (minify-errors-in-prod): Unminified error message in production build!' + ); + return; + } + prodErrorId = parseInt(prodErrorId, 10); + + // Import ReactErrorProd + const reactErrorProdIdentfier = addDefault( + path, + paths.appRoot + '/errors/ErrorProd.js', + { + nameHint: 'InvariantErrorProd', + } + ); + + // Outputs: + // throw ReactErrorProd(ERR_CODE, adj, noun); + const prodThrow = t.throwStatement( + t.callExpression(reactErrorProdIdentfier, [ + t.numericLiteral(prodErrorId), + ...errorMsgExpressions, + ]) + ); + + // Outputs: + // if (!condition) { + // if (__DEV__) { + // throw ReactError(`A ${adj} message that contains ${noun}`); + // } else { + // throw ReactErrorProd(ERR_CODE, adj, noun); + // } + // } + path.replaceWith( + t.ifStatement( + t.unaryExpression('!', condition), + t.blockStatement([ + t.ifStatement( + DEV_EXPRESSION, + t.blockStatement([devThrow]), + t.blockStatement([prodThrow]) + ), + ]) + ) + ); + } + }, + }, + }; +} diff --git a/src/index.ts b/src/index.ts index 69245f504..9bd4c7c56 100755 --- a/src/index.ts +++ b/src/index.ts @@ -279,7 +279,14 @@ prog ) .example('watch --verbose') .option('--tsconfig', 'Specify custom tsconfig path') - .example('build --tsconfig ./tsconfig.foo.json') + .example('watch --tsconfig ./tsconfig.foo.json') + .option( + '--extractErrors', + 'Extract errors to codes.json and provide a url for decoding.' + ) + .example( + 'build --extractErrors=https://reactjs.org/docs/error-decoder.html?invariant=' + ) .action(async (dirtyOpts: any) => { const opts = await normalizeOpts(dirtyOpts); const buildConfigs = createBuildConfigs(opts); @@ -337,6 +344,13 @@ prog .example('build --format cjs,esm') .option('--tsconfig', 'Specify custom tsconfig path') .example('build --tsconfig ./tsconfig.foo.json') + .option( + '--extractErrors', + 'Extract errors to codes.json and provide a url for decoding.' + ) + .example( + 'build --extractErrors=https://reactjs.org/docs/error-decoder.html?invariant=' + ) .action(async (dirtyOpts: any) => { const opts = await normalizeOpts(dirtyOpts); const buildConfigs = createBuildConfigs(opts); diff --git a/templates/react/README.md b/templates/react/README.md index f1db65f63..697c66e50 100644 --- a/templates/react/README.md +++ b/templates/react/README.md @@ -122,7 +122,7 @@ The Playground is just a simple [Parcel](https://parceljs.org) app, you can depl cd example # if not already in the example folder npm run build # builds to dist netlify deploy # deploy the dist folder -``` +``` Alternatively, if you already have a git repo connected, you can set up continuous deployment with Netlify: diff --git a/templates/react/example/index.html b/templates/react/example/index.html index e3298dba4..547e2e042 100644 --- a/templates/react/example/index.html +++ b/templates/react/example/index.html @@ -1,16 +1,14 @@ + + + + + Playground + - - - - - Playground - - - -
- - - - \ No newline at end of file + +
+ + + diff --git a/yarn.lock b/yarn.lock index fc1315708..76aaf32e1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -859,10 +859,10 @@ dependencies: "@types/node" "*" -"@types/fs-extra@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-7.0.0.tgz#9c4ad9e1339e7448a76698829def1f159c1b636c" - integrity sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA== +"@types/fs-extra@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.0.tgz#d3e2c313ca29f95059f198dd60d1f774642d4b25" + integrity sha512-bCtL5v9zdbQW86yexOlXWTEGvLNqWxMFyi7gQA7Gcthbezr2cPSOb8SkESVKA937QD5cIwOFLDFt0MQoXOEr9Q== dependencies: "@types/node" "*" @@ -1206,6 +1206,11 @@ ansi-regex@^4.0.0, ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1362,6 +1367,15 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + babel-jest@^24.8.0: version "24.8.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.8.0.tgz#5c15ff2b28e20b0f45df43fe6b7f2aae93dba589" @@ -1375,6 +1389,13 @@ babel-jest@^24.8.0: chalk "^2.4.2" slash "^2.0.0" +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= + dependencies: + babel-runtime "^6.22.0" + babel-plugin-annotate-pure-calls@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/babel-plugin-annotate-pure-calls/-/babel-plugin-annotate-pure-calls-0.4.0.tgz#78aa00fd878c4fcde4d49f3da397fcf5defbcce8" @@ -1419,6 +1440,44 @@ babel-preset-jest@^24.6.0: "@babel/plugin-syntax-object-rest-spread" "^7.0.0" babel-plugin-jest-hoist "^24.6.0" +babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= + dependencies: + 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" + +babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -1690,6 +1749,14 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camel-case@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + camelcase@*, camelcase@^5.0.0: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -1717,6 +1784,17 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1933,7 +2011,7 @@ core-js-pure@3.1.4: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.4.tgz#5fa17dc77002a169a3566cc48dc774d2e13e3769" integrity sha512-uJ4Z7iPNwiu1foygbcZYJsJs1jiXrTTCvxfLDXNhI/I+NHbSIEyr548y4fcsCEyWY0XgfAG/qqaunJ1SThHenA== -core-js@^2.6.5: +core-js@^2.4.0, core-js@^2.6.5: version "2.6.9" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== @@ -2067,7 +2145,7 @@ date-now@^0.1.4: resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= -debug@^2.2.0, debug@^2.3.3: +debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -2307,7 +2385,7 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" -escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -2736,6 +2814,11 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== + globalyzer@^0.1.0: version "0.1.4" resolved "https://registry.yarnpkg.com/globalyzer/-/globalyzer-0.1.4.tgz#bc8e273afe1ac7c24eea8def5b802340c5cc534f" @@ -2788,6 +2871,13 @@ har-validator@~5.1.0: ajv "^6.5.5" har-schema "^2.0.0" +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -3662,6 +3752,11 @@ js-levenshtein@^1.1.3: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= + js-yaml@^3.13.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" @@ -3874,7 +3969,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash@^4.17.11: +lodash@^4.17.11, lodash@^4.17.4: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== @@ -3902,6 +3997,11 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= + lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -4216,6 +4316,13 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== + dependencies: + lower-case "^1.1.1" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -4594,6 +4701,14 @@ parse5@4.0.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== +pascal-case@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e" + integrity sha1-LVeNNFX2YNpl7KGO+VtODekSdh4= + dependencies: + camel-case "^3.0.0" + upper-case-first "^1.1.0" + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -4984,6 +5099,11 @@ regenerate@^1.4.0: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + regenerator-runtime@^0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" @@ -5736,6 +5856,11 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -5860,6 +5985,11 @@ to-arraybuffer@^1.0.0: resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -6110,6 +6240,18 @@ upath@^1.1.1: resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== +upper-case-first@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115" + integrity sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU= + dependencies: + upper-case "^1.1.1" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"