diff --git a/.eslintrc.js b/.eslintrc.js index 1cfed9bb2..bb1b7375f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,6 +17,7 @@ module.exports = { 'class-methods-use-this': 0, // fixme 'import/no-cycle': 0, // fixme 'import/no-extraneous-dependencies': 0, // fixme + 'import/no-unresolved': 'off', // fixme, allows JS files to import TS files 'no-underscore-dangle': 0, // fixme 'prefer-destructuring': ['error', { object: true, array: false }], // fixme }, diff --git a/babel.config.js b/babel.config.js index 4aa7e6667..bc97bf102 100644 --- a/babel.config.js +++ b/babel.config.js @@ -16,6 +16,20 @@ module.exports = api => { '@babel/plugin-proposal-object-rest-spread', '@babel/plugin-transform-object-assign', ], + overrides: [ + { + test: ['./src/**/*.ts', './src/**/*.tsx'], + presets: [ + [ + '@babel/preset-typescript', + { + isTSX: true, + allExtensions: true, + }, + ], + ], + }, + ], env: { production: { plugins: [['react-remove-properties', { properties: ['data-testid'] }]], diff --git a/build/webpack.common.config.js b/build/webpack.common.config.js index 396abac39..e24712e77 100644 --- a/build/webpack.common.config.js +++ b/build/webpack.common.config.js @@ -16,7 +16,7 @@ module.exports = language => { module: { rules: [ { - test: /\.js$/, + test: /\.(js|ts|tsx)$/, loader: 'babel-loader', include: [path.resolve('src/lib')], }, @@ -66,6 +66,7 @@ module.exports = language => { 'box-elements-messages': path.resolve(`node_modules/box-ui-elements/i18n/${language}`), 'react-intl-locale-data': path.resolve(`node_modules/react-intl/locale-data/${locale}`), }, + extensions: ['.tsx', '.ts', '.js'], }, stats: { assets: true, diff --git a/lint-staged.config.js b/lint-staged.config.js index edb14069d..cf3654e4d 100644 --- a/lint-staged.config.js +++ b/lint-staged.config.js @@ -4,4 +4,6 @@ module.exports = { '*.html': ['prettier --write --parser=html', 'git add'], '*.md': ['prettier --write --parser=markdown', 'git add'], '*.scss': ['prettier --write --parser=scss', 'stylelint --syntax scss --fix', 'git add'], + '*.ts': ['eslint --ext=.ts --fix', 'git add'], + '*.tsx': ['eslint --ext=.tsx --fix', 'git add'], }; diff --git a/package.json b/package.json index af717c91c..5e3f23e6c 100644 --- a/package.json +++ b/package.json @@ -14,11 +14,13 @@ "@babel/plugin-transform-object-assign": "^7.2.0", "@babel/preset-env": "^7.5.5", "@babel/preset-react": "^7.0.0", + "@babel/preset-typescript": "^7.7.7", "@box/frontend": "^6.0.0", "@box/languages": "^1.0.0", "@commitlint/cli": "^8.2.0", "@commitlint/config-conventional": "^8.2.0", "@commitlint/travis-cli": "^8.2.0", + "@types/lodash": "^4.14.149", "@typescript-eslint/eslint-plugin": "^2.13.0", "@typescript-eslint/parser": "^2.13.0", "autoprefixer": "^9.6.1", @@ -130,6 +132,7 @@ "lint": "npm-run-all lint:*", "lint:css": "NODE_ENV=dev yarn stylelint 'src/lib/**/*.scss'", "lint:js": "NODE_ENV=dev yarn eslint src/lib", + "lint:ts": "tsc && eslint --ext=.tsx,.ts --max-warnings=0 .", "release": "yarn setup && yarn clean && yarn build:i18n && yarn lint && yarn test && yarn build:prod", "release:major": "./build/release.sh -m", "release:minor": "./build/release.sh -n", diff --git a/src/lib/api.js b/src/lib/api.js deleted file mode 100644 index b6e625d8e..000000000 --- a/src/lib/api.js +++ /dev/null @@ -1,200 +0,0 @@ -import axios from 'axios'; -import DownloadReachability from './DownloadReachability'; -import MetadataAPI from './metadataAPI'; - -/** - * Retrieves JSON from response. - * - * @private - * @param {Response} response - Response to parse - * @return {Promise|Response} Response if 204 or 202, otherwise promise that resolves with JSON - */ -const parseResponse = response => { - if (response.status === 204 || response.status === 202) { - return response; - } - - return response.data; -}; - -/** - * Filter empty values from the http request options object - * - * @private - * @param {Object} options - The request options - * @return {Object} The cleaned request options - */ -const filterOptions = (options = {}) => { - const result = {}; - - Object.keys(options).forEach(key => { - if (options[key] !== undefined && options[key] !== null && options[key] !== '') { - result[key] = options[key]; - } - }); - - return result; -}; - -/** - * Helper function to convert an http error to the format Preview expects - * - * @private - * @param {Object} response - Axios error response - * @throws {Error} - Throws when an error response object exists - * @return {void} - */ -const handleError = ({ response }) => { - if (response) { - const error = new Error(response.statusText); - error.response = response; // Need to pass response through so we can see what kind of HTTP error this was - throw error; - } -}; - -/** - * Pass through transformer if the response type is text - * @param {Object} data - * @return {Object} - */ -const transformTextResponse = data => data; - -export default class Api { - /** - * [constructor] - * - * @return {Api} Instance of the API - */ - constructor() { - this.client = axios.create(); - this.metadata = new MetadataAPI(this); - this.reachability = new DownloadReachability(this); - } - - /** - * Adds a function that intercepts an http response - - * @public - * @param {Function} responseInterceptor - Function that gets called on each response - * @return {void} - */ - addResponseInterceptor(responseInterceptor) { - if (typeof responseInterceptor === 'function') { - this.client.interceptors.response.use(responseInterceptor); - } - } - - /** - * Adds a function that intercepts an http request - * @public - * @param {Function} requestInterceptor - function that gets called on each request - * @return {void} - - */ - addRequestInterceptor(requestInterceptor) { - if (typeof requestInterceptor === 'function') { - this.client.interceptors.request.use(requestInterceptor); - } - } - - /** - * Ejects all interceptors - * @public - * - * @return {void} - */ - ejectInterceptors() { - ['response', 'request'].forEach(interceptorType => { - this.client.interceptors[interceptorType].handlers.forEach((interceptor, index) => { - this.client.interceptors[interceptorType].eject(index); - }); - }); - } - - /** - * HTTP GETs a URL - * - * @public - * @param {string} url - The URL to fetch - * @param {Object} options - The request options - * @return {Promise} - HTTP response - */ - get(url, { type: responseType = 'json', ...options } = {}) { - return this.xhr(url, { method: 'get', responseType, ...options }); - } - - /** - * HTTP HEAD a URL - * - * @public - * @param {string} url - The URL to fetch - * @param {Object} options - The request options - * @return {Promise} HTTP response - */ - head(url, options = {}) { - return this.xhr(url, { method: 'head', ...options }); - } - - /** - * HTTP POSTs a URL with JSON data - * - * @public - * @param {string} url - The URL to fetch - * @param {Object} data - JS Object representation of JSON data to send - * @param {Object} options - The request options - * @return {Promise} HTTP response - */ - post(url, data, options = {}) { - return this.xhr(url, { method: 'post', data, ...options }); - } - - /** - * HTTP DELETEs a URL with JSON data - * - * @public - * @param {string} url - The URL to fetch - * @param {Object} data - JS Object representation of JSON data to send - * @param {Object} options - The request options - * @return {Promise} HTTP response - */ - delete(url, data, options = {}) { - return this.xhr(url, { method: 'delete', data, ...options }); - } - - /** - * HTTP PUTs a url with JSON data - * - * @public - * @param {string} url - The url to fetch - * @param {Object} data - JS Object representation of JSON data to send - * @param {Object} options - The request options - * @return {Promise} HTTP response - */ - put(url, data, options = {}) { - return this.xhr(url, { method: 'put', data, ...options }); - } - - /** - * Wrapper function for XHR post put and delete - * - * @private - * @param {string} url - The URL for XHR - * @param {Object} options - The request options - * @return {Promise} - XHR promise - */ - xhr(url, options = {}) { - if (!(this instanceof Api)) { - return Promise.reject(new SyntaxError('Invalid invocation')); - } - - let transformResponse; - - if (options.responseType === 'text') { - transformResponse = transformTextResponse; - } - - return this.client(url, filterOptions({ transformResponse, ...options })) - .then(parseResponse) - .catch(handleError); - } -} diff --git a/src/lib/api.ts b/src/lib/api.ts new file mode 100644 index 000000000..7a78adc61 --- /dev/null +++ b/src/lib/api.ts @@ -0,0 +1,104 @@ +import axios, { + AxiosError, + AxiosInstance, + AxiosInterceptorManager, + AxiosPromise, + AxiosRequestConfig, + AxiosResponse, + ResponseType, +} from 'axios'; +import pickBy from 'lodash/pickBy'; +import DownloadReachability from './DownloadReachability'; +import MetadataAPI from './metadataAPI'; + +export type APIGetConfig = { type?: ResponseType } & AxiosRequestConfig; +export type APIError = { response: AxiosResponse } & Error; +export type APIPromise = Promise; + +const filterOptions = (options: AxiosRequestConfig = {}): AxiosRequestConfig => { + return pickBy(options, (value: keyof AxiosRequestConfig) => value !== undefined && value !== null); +}; + +const handleError = ({ response }: AxiosError): void => { + if (response) { + const error = new Error(response.statusText) as APIError; + error.response = response; // Need to pass response through so we can see what kind of HTTP error this was + throw error; + } +}; +const parseResponse = (response: AxiosResponse): AxiosResponse | AxiosResponse['data'] => { + if (response.status === 204 || response.status === 202) { + return response; + } + + return response.data; +}; + +const transformTextResponse = (data: D): D => data; + +export default class Api { + client: AxiosInstance; + + interceptors: number[] = []; + + metadata: MetadataAPI; + + reachability: DownloadReachability; + + constructor() { + this.client = axios.create(); + this.metadata = new MetadataAPI(this); + this.reachability = new DownloadReachability(this); + } + + addResponseInterceptor(responseInterceptor: AxiosInterceptorManager): void { + if (typeof responseInterceptor === 'function') { + this.interceptors.push(this.client.interceptors.response.use(responseInterceptor)); + } + } + + addRequestInterceptor(requestInterceptor: AxiosInterceptorManager): void { + if (typeof requestInterceptor === 'function') { + this.interceptors.push(this.client.interceptors.request.use(requestInterceptor)); + } + } + + ejectInterceptors(): void { + this.interceptors.forEach(interceptorIndex => { + this.client.interceptors.request.eject(interceptorIndex); + this.client.interceptors.response.eject(interceptorIndex); + }); + } + + delete(url: string, data: D, options: AxiosRequestConfig = {}): AxiosPromise { + return this.xhr(url, { method: 'delete', data, ...options }); + } + + get(url: string, { type: responseType = 'json', ...options }: APIGetConfig = {}): AxiosPromise { + return this.xhr(url, { method: 'get', responseType, ...options }); + } + + head(url: string, options: AxiosRequestConfig = {}): AxiosPromise { + return this.xhr(url, { method: 'head', ...options }); + } + + post(url: string, data: D, options: AxiosRequestConfig = {}): AxiosPromise { + return this.xhr(url, { method: 'post', data, ...options }); + } + + put(url: string, data: D, options: AxiosRequestConfig = {}): AxiosPromise { + return this.xhr(url, { method: 'put', data, ...options }); + } + + xhr(url: string, options: AxiosRequestConfig = {}): AxiosPromise { + let transformResponse; + + if (options.responseType === 'text') { + transformResponse = transformTextResponse; + } + + return this.client(url, filterOptions({ transformResponse, ...options })) + .then(parseResponse) + .catch(handleError); + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..19a790f74 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "@box/frontend/ts/tsconfig.json", + "include": ["./src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/yarn.lock b/yarn.lock index d832681fa..77d2c6000 100644 --- a/yarn.lock +++ b/yarn.lock @@ -40,6 +40,16 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.7.4": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.7.tgz#859ac733c44c74148e1a72980a64ec84b85f4f45" + integrity sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ== + dependencies: + "@babel/types" "^7.7.4" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" @@ -84,6 +94,18 @@ "@babel/helper-replace-supers" "^7.5.5" "@babel/helper-split-export-declaration" "^7.4.4" +"@babel/helper-create-class-features-plugin@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.7.4.tgz#fce60939fd50618610942320a8d951b3b639da2d" + integrity sha512-l+OnKACG4uiDHQ/aJT8dwpR+LhCJALxL0mJ6nzjB25e5IPwqV1VOsY7ah6UB1DG+VOXAIMtuC54rFJGiHkxjgA== + dependencies: + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-member-expression-to-functions" "^7.7.4" + "@babel/helper-optimise-call-expression" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/helper-define-map@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz#3dec32c2046f37e09b28c93eb0b103fd2a25d369" @@ -110,6 +132,15 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-function-name@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e" + integrity sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ== + dependencies: + "@babel/helper-get-function-arity" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/types" "^7.7.4" + "@babel/helper-get-function-arity@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" @@ -117,6 +148,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-get-function-arity@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0" + integrity sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA== + dependencies: + "@babel/types" "^7.7.4" + "@babel/helper-hoist-variables@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" @@ -131,6 +169,13 @@ dependencies: "@babel/types" "^7.5.5" +"@babel/helper-member-expression-to-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz#356438e2569df7321a8326644d4b790d2122cb74" + integrity sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw== + dependencies: + "@babel/types" "^7.7.4" + "@babel/helper-module-imports@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" @@ -157,6 +202,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-optimise-call-expression@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz#034af31370d2995242aa4df402c3b7794b2dcdf2" + integrity sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg== + dependencies: + "@babel/types" "^7.7.4" + "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" @@ -190,6 +242,16 @@ "@babel/traverse" "^7.5.5" "@babel/types" "^7.5.5" +"@babel/helper-replace-supers@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz#3c881a6a6a7571275a72d82e6107126ec9e2cdd2" + integrity sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.7.4" + "@babel/helper-optimise-call-expression" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" + "@babel/helper-simple-access@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" @@ -205,6 +267,13 @@ dependencies: "@babel/types" "^7.4.4" +"@babel/helper-split-export-declaration@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8" + integrity sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug== + dependencies: + "@babel/types" "^7.7.4" + "@babel/helper-wrap-function@^7.1.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" @@ -238,6 +307,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.5.tgz#02f077ac8817d3df4a832ef59de67565e71cca4b" integrity sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g== +"@babel/parser@^7.7.4": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.7.tgz#1b886595419cf92d811316d5b715a53ff38b4937" + integrity sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw== + "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" @@ -338,6 +412,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-typescript@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.7.4.tgz#5d037ffa10f3b25a16f32570ebbe7a8c2efa304b" + integrity sha512-77blgY18Hud4NM1ggTA8xVT/dBENQf17OpiToSa2jSmEY3fWXD2jwrdVlO4kq5yzUTeF15WSQ6b4fByNvJcjpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-arrow-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" @@ -614,6 +695,15 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-typescript@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.7.4.tgz#2974fd05f4e85c695acaf497f432342de9fc0636" + integrity sha512-X8e3tcPEKnwwPVG+vP/vSqEShkwODOEeyQGod82qrIuidwIrfnsGn11qPM1jBLF4MqguTXXYzm58d0dY+/wdpg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.7.4" + "@babel/plugin-transform-unicode-regex@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f" @@ -690,6 +780,14 @@ "@babel/plugin-transform-react-jsx-self" "^7.0.0" "@babel/plugin-transform-react-jsx-source" "^7.0.0" +"@babel/preset-typescript@^7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.7.7.tgz#69ddea54e8b4e491ccbf94147e673b2ac6e11e2e" + integrity sha512-Apg0sCTovsSA+pEaI8efnA44b9x4X/7z4P8vsWMiN8rSUaM4y4+Shl5NMWnMl6njvt96+CEb6jwpXAKYAVCSQA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.7.4" + "@babel/runtime@^7.4.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132" @@ -713,6 +811,15 @@ "@babel/parser" "^7.4.4" "@babel/types" "^7.4.4" +"@babel/template@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" + integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" + "@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.5.tgz#f664f8f368ed32988cd648da9f72d5ca70f165bb" @@ -728,6 +835,21 @@ globals "^11.1.0" lodash "^4.17.13" +"@babel/traverse@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" + integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + "@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.5.tgz#97b9f728e182785909aa4ab56264f090a028d18a" @@ -737,6 +859,15 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" + integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@box/frontend@^6.0.0": version "6.0.0" resolved "https://registry.yarnpkg.com/@box/frontend/-/frontend-6.0.0.tgz#5ffca35f1bf49e073cf4dc9a52b76bd5afae948a" @@ -1060,6 +1191,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== +"@types/lodash@^4.14.149": + version "4.14.149" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" + integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"