diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bdc06cbb0cf..16f419383503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +- [react] feat: Add @sentry/react package (#2631) ## 5.16.0 diff --git a/package.json b/package.json index 762e7ab7f25f..69935f2abd94 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "packages/integrations", "packages/minimal", "packages/node", - "packages/opentracing", + "packages/react", "packages/types", "packages/typescript", "packages/utils" diff --git a/packages/react/.npmignore b/packages/react/.npmignore new file mode 100644 index 000000000000..14e80551ae7c --- /dev/null +++ b/packages/react/.npmignore @@ -0,0 +1,4 @@ +* +!/dist/**/* +!/esm/**/* +*.tsbuildinfo diff --git a/packages/react/LICENSE b/packages/react/LICENSE new file mode 100644 index 000000000000..8b42db873c95 --- /dev/null +++ b/packages/react/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2019, Sentry +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/react/README.md b/packages/react/README.md new file mode 100644 index 000000000000..8df1272d44af --- /dev/null +++ b/packages/react/README.md @@ -0,0 +1,13 @@ +

+ + + +
+

+ +# Official Sentry SDK for ReactJS + +## Links + +- [Official SDK Docs](https://docs.sentry.io/quickstart/) +- [TypeDoc](http://getsentry.github.io/sentry-javascript/) diff --git a/packages/react/package.json b/packages/react/package.json new file mode 100644 index 000000000000..2b3dc11c4a57 --- /dev/null +++ b/packages/react/package.json @@ -0,0 +1,88 @@ +{ + "name": "@sentry/react", + "version": "5.16.0", + "description": "Offical Sentry SDK for React.js", + "repository": "git://github.com/getsentry/sentry-javascript.git", + "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/react", + "author": "Sentry", + "license": "BSD-3-Clause", + "engines": { + "node": ">=6" + }, + "main": "dist/index.js", + "module": "esm/index.js", + "types": "dist/index.d.ts", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@sentry/browser": "5.16.0", + "@sentry/types": "5.16.0", + "@sentry/utils": "5.16.0", + "hoist-non-react-statics": "^3.3.2", + "tslib": "^1.9.3" + }, + "peerDependencies": { + "react": "^16.0.0", + "react-dom": "^16.0.0" + }, + "devDependencies": { + "@types/hoist-non-react-statics": "^3.3.1", + "@types/react": "^16.9.35", + "@types/react-test-renderer": "^16.9.2", + "jest": "^24.7.1", + "npm-run-all": "^4.1.2", + "prettier": "^1.17.0", + "prettier-check": "^2.0.0", + "react": "^16.0.0", + "react-dom": "^16.0.0", + "react-test-renderer": "^16.13.1", + "rimraf": "^2.6.3", + "tslint": "^5.16.0", + "tslint-react": "^5.0.0", + "typescript": "^3.5.1" + }, + "scripts": { + "build": "run-p build:es5 build:esm", + "build:es5": "tsc -p tsconfig.build.json", + "build:esm": "tsc -p tsconfig.esm.json", + "build:watch": "run-p build:watch:es5 build:watch:esm", + "build:watch:es5": "tsc -p tsconfig.build.json -w --preserveWatchOutput", + "build:watch:esm": "tsc -p tsconfig.esm.json -w --preserveWatchOutput", + "clean": "rimraf dist coverage build esm", + "link:yarn": "yarn link", + "lint": "run-s lint:prettier lint:tslint", + "lint:prettier": "prettier-check \"{src,test}/**/*.{ts,tsx}\"", + "lint:tslint": "tslint -t stylish -p .", + "lint:tslint:json": "tslint --format json -p . | tee lint-results.json", + "fix": "run-s fix:tslint fix:prettier", + "fix:prettier": "prettier --write \"{src,test}/**/*.{ts,tsx}\"", + "fix:tslint": "tslint --fix -t stylish -p .", + "test": "jest", + "test:watch": "jest --watch" + }, + "jest": { + "collectCoverage": true, + "transform": { + "^.+\\.ts$": "ts-jest", + "^.+\\.tsx$": "ts-jest" + }, + "moduleFileExtensions": [ + "js", + "ts", + "tsx" + ], + "testEnvironment": "jsdom", + "testMatch": [ + "**/*.test.ts", + "**/*.test.tsx" + ], + "globals": { + "ts-jest": { + "tsConfig": "./tsconfig.json", + "diagnostics": false + } + } + }, + "sideEffects": false +} diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts new file mode 100644 index 000000000000..93fa1c640dcc --- /dev/null +++ b/packages/react/src/index.ts @@ -0,0 +1,3 @@ +export * from '@sentry/browser'; + +export { Profiler, withProfiler } from './profiler'; diff --git a/packages/react/src/profiler.tsx b/packages/react/src/profiler.tsx new file mode 100644 index 000000000000..16373639c18a --- /dev/null +++ b/packages/react/src/profiler.tsx @@ -0,0 +1,119 @@ +import { getCurrentHub } from '@sentry/browser'; +import { Integration, IntegrationClass } from '@sentry/types'; +import { logger } from '@sentry/utils'; +import * as hoistNonReactStatic from 'hoist-non-react-statics'; +import * as React from 'react'; + +export const UNKNOWN_COMPONENT = 'unknown'; + +const TRACING_GETTER = ({ + id: 'Tracing', +} as any) as IntegrationClass; + +/** + * + * Based on implementation from Preact: + * https:github.com/preactjs/preact/blob/9a422017fec6dab287c77c3aef63c7b2fef0c7e1/hooks/src/index.js#L301-L313 + * + * Schedule a callback to be invoked after the browser has a chance to paint a new frame. + * Do this by combining requestAnimationFrame (rAF) + setTimeout to invoke a callback after + * the next browser frame. + * + * Also, schedule a timeout in parallel to the the rAF to ensure the callback is invoked + * even if RAF doesn't fire (for example if the browser tab is not visible) + * + * This is what we use to tell if a component activity has finished + * + */ +function afterNextFrame(callback: Function): void { + let timeout: number | undefined; + let raf: number; + + const done = () => { + window.clearTimeout(timeout); + window.cancelAnimationFrame(raf); + window.setTimeout(callback); + }; + + raf = window.requestAnimationFrame(done); + timeout = window.setTimeout(done, 100); +} + +const getInitActivity = (componentDisplayName: string): number | null => { + const tracingIntegration = getCurrentHub().getIntegration(TRACING_GETTER); + + if (tracingIntegration !== null) { + // tslint:disable-next-line:no-unsafe-any + const activity = (tracingIntegration as any).constructor.pushActivity(componentDisplayName, { + description: `<${componentDisplayName}>`, + op: 'react', + }); + + // tslint:disable-next-line: no-unsafe-any + return activity; + } + + logger.warn( + `Unable to profile component ${componentDisplayName} due to invalid Tracing Integration. Please make sure to setup the Tracing integration.`, + ); + return null; +}; + +interface ProfilerProps { + componentDisplayName?: string; +} + +class Profiler extends React.Component { + public activity: number | null; + public constructor(props: ProfilerProps) { + super(props); + + const { componentDisplayName = UNKNOWN_COMPONENT } = this.props; + + this.activity = getInitActivity(componentDisplayName); + } + + public componentDidMount(): void { + afterNextFrame(this.finishProfile); + } + + public componentWillUnmount(): void { + afterNextFrame(this.finishProfile); + } + + public finishProfile = () => { + if (!this.activity) { + return; + } + + const tracingIntegration = getCurrentHub().getIntegration(TRACING_GETTER); + if (tracingIntegration !== null) { + // tslint:disable-next-line:no-unsafe-any + (tracingIntegration as any).constructor.popActivity(this.activity); + this.activity = null; + } + }; + + public render(): React.ReactNode { + return this.props.children; + } +} + +function withProfiler

(WrappedComponent: React.ComponentType

): React.FC

{ + const componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT; + + const Wrapped: React.FC

= (props: P) => ( + + + + ); + + Wrapped.displayName = `profiler(${componentDisplayName})`; + + // Copy over static methods from Wrapped component to Profiler HOC + // See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over + hoistNonReactStatic(Wrapped, WrappedComponent); + return Wrapped; +} + +export { withProfiler, Profiler }; diff --git a/packages/react/test/profiler.test.tsx b/packages/react/test/profiler.test.tsx new file mode 100644 index 000000000000..fa208211010c --- /dev/null +++ b/packages/react/test/profiler.test.tsx @@ -0,0 +1,70 @@ +import * as React from 'react'; +import { create } from 'react-test-renderer'; + +import { UNKNOWN_COMPONENT, withProfiler } from '../src/profiler'; + +const mockPushActivity = jest.fn().mockReturnValue(1); +const mockPopActivity = jest.fn(); + +jest.mock('@sentry/browser', () => ({ + getCurrentHub: () => ({ + getIntegration: (_: string) => { + class MockIntegration { + public constructor(name: string) { + this.name = name; + } + public name: string; + public setupOnce: () => void = jest.fn(); + public static pushActivity: () => void = mockPushActivity; + public static popActivity: () => void = mockPopActivity; + } + + return new MockIntegration('test'); + }, + }), +})); + +describe('withProfiler', () => { + it('sets displayName properly', () => { + const TestComponent = () =>

Hello World

; + + const ProfiledComponent = withProfiler(TestComponent); + expect(ProfiledComponent.displayName).toBe('profiler(TestComponent)'); + }); + + describe('Tracing Integration', () => { + beforeEach(() => { + jest.useFakeTimers(); + mockPushActivity.mockClear(); + mockPopActivity.mockClear(); + }); + + it('is called with popActivity() when unmounted', () => { + const ProfiledComponent = withProfiler(() =>

Hello World

); + + expect(mockPopActivity).toHaveBeenCalledTimes(0); + + const profiler = create(); + profiler.unmount(); + + jest.runAllTimers(); + + expect(mockPopActivity).toHaveBeenCalledTimes(1); + expect(mockPopActivity).toHaveBeenLastCalledWith(1); + }); + + describe('pushActivity()', () => { + it('is called when mounted', () => { + const ProfiledComponent = withProfiler(() =>

Testing

); + + expect(mockPushActivity).toHaveBeenCalledTimes(0); + create(); + expect(mockPushActivity).toHaveBeenCalledTimes(1); + expect(mockPushActivity).toHaveBeenLastCalledWith(UNKNOWN_COMPONENT, { + description: `<${UNKNOWN_COMPONENT}>`, + op: 'react', + }); + }); + }); + }); +}); diff --git a/packages/react/tsconfig.build.json b/packages/react/tsconfig.build.json new file mode 100644 index 000000000000..b1470d524cab --- /dev/null +++ b/packages/react/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "jsx": "react" + }, + "include": ["src/**/*"] +} diff --git a/packages/react/tsconfig.esm.json b/packages/react/tsconfig.esm.json new file mode 100644 index 000000000000..1ed43d018cc7 --- /dev/null +++ b/packages/react/tsconfig.esm.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.esm.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "esm", + "jsx": "react" + }, + "include": ["src/**/*"] +} diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json new file mode 100644 index 000000000000..d627bc66b496 --- /dev/null +++ b/packages/react/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.build.json", + "include": ["src/**/*.ts", "test/**/*.ts", "src/**/*.tsx", "test/**/*.tsx"], + "exclude": ["dist"], + "compilerOptions": { + "rootDir": ".", + "types": ["jest"] + } +} diff --git a/packages/react/tslint.json b/packages/react/tslint.json new file mode 100644 index 000000000000..1c16df5658e5 --- /dev/null +++ b/packages/react/tslint.json @@ -0,0 +1,11 @@ +{ + "extends": ["@sentry/typescript/tslint", "tslint-react"], + "rules": { + "no-implicit-dependencies": [ + true, + "dev" + ], + "variable-name": false, + "completed-docs": false + } +} diff --git a/typedoc.js b/typedoc.js index b7ba773c464b..178b68e58212 100644 --- a/typedoc.js +++ b/typedoc.js @@ -9,7 +9,6 @@ module.exports = { '**/dist/**/*', '**/esm/**/*', '**/build/**/*', - '**/packages/opentracing/**/*', '**/packages/typescript/**/*', '**/dangerfile.ts', ], diff --git a/yarn.lock b/yarn.lock index 65a51f8eef12..abf8e70b088b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1295,6 +1295,14 @@ resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.3.tgz#b672cfaac25cbbc634a0fd92c515f66faa18dbca" integrity sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ== +"@types/hoist-non-react-statics@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/istanbul-lib-coverage@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz#1eb8c033e98cf4e1a4cedcaf8bcafe8cb7591e85" @@ -1359,11 +1367,31 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.7.tgz#85dbb71c510442d00c0631f99dae957ce44fd104" integrity sha512-suFHr6hcA9mp8vFrZTgrmqW2ZU3mbWsryQtQlY/QvwTISCw7nw/j+bCQPPohqmskhmqa5wLNuMHTTsc+xf1MQg== +"@types/prop-types@*": + version "15.7.3" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" + integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + "@types/range-parser@*": version "1.2.3" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== +"@types/react-test-renderer@^16.9.2": + version "16.9.2" + resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.9.2.tgz#e1c408831e8183e5ad748fdece02214a7c2ab6c5" + integrity sha512-4eJr1JFLIAlWhzDkBCkhrOIWOvOxcCAfQh+jiKg7l/nNZcCIL2MHl2dZhogIFKyHzedVWHaVP1Yydq/Ruu4agw== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^16.9.35": + version "16.9.35" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.35.tgz#a0830d172e8aadd9bd41709ba2281a3124bbd368" + integrity sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + "@types/request@^2.48.1": version "2.48.1" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.1.tgz#e402d691aa6670fbbff1957b15f1270230ab42fa" @@ -3754,6 +3782,11 @@ cssstyle@^1.0.0, cssstyle@^1.1.1: dependencies: cssom "0.3.x" +csstype@^2.2.0: + version "2.6.10" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b" + integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w== + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -5454,6 +5487,13 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -7280,7 +7320,7 @@ longest@^1.0.1: resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= -loose-envify@^1.0.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -8180,7 +8220,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -8895,6 +8935,15 @@ promzard@^0.3.0: dependencies: read "1" +prop-types@^15.6.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -9081,11 +9130,45 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-dom@^16.0.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" + integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.19.1" + +react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-is@^16.8.4: version "16.8.4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.4.tgz#90f336a68c3a29a096a3d648ab80e87ec61482a2" integrity sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA== +react-test-renderer@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.1.tgz#de25ea358d9012606de51e012d9742e7f0deabc1" + integrity sha512-Sn2VRyOK2YJJldOqoh8Tn/lWQ+ZiKhyZTPtaO0Q6yNj+QDbmRkVFap6pZPy3YQk8DScRDfyqm/KxKYP9gCMRiQ== + dependencies: + object-assign "^4.1.1" + prop-types "^15.6.2" + react-is "^16.8.6" + scheduler "^0.19.1" + +react@^16.0.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" + integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + read-cmd-shim@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" @@ -9688,6 +9771,14 @@ saxes@^3.1.9: dependencies: xmlchars "^1.3.1" +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" + integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" @@ -10778,6 +10869,13 @@ tslint-consistent-codestyle@^1.15.1: tslib "^1.7.1" tsutils "^2.29.0" +tslint-react@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tslint-react/-/tslint-react-5.0.0.tgz#d0ae644e8163bdd3e134012e9353094904e8dd44" + integrity sha512-/IbcSmoBPlFic8kQaRfQ4knTY4mivwo5LVzvozvX6Dyu2ynEnrh1dIcR2ujjyp/IodXqY/H5GbxFxSMo/Kf2Hg== + dependencies: + tsutils "^3.17.1" + tslint@^5.16.0: version "5.16.0" resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.16.0.tgz#ae61f9c5a98d295b9a4f4553b1b1e831c1984d67" @@ -10803,6 +10901,13 @@ tsutils@^2.29.0: dependencies: tslib "^1.8.1" +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + dependencies: + tslib "^1.8.1" + tsutils@^3.5.0: version "3.8.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.8.0.tgz#7a3dbadc88e465596440622b65c04edc8e187ae5" @@ -10909,6 +11014,11 @@ typescript@^3.4.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== +typescript@^3.5.1: + version "3.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a" + integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ== + uglify-js@^2.6: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"