From 0cb59794753987290a5cc97701ef3bfdda287533 Mon Sep 17 00:00:00 2001 From: Ville Immonen Date: Wed, 29 Apr 2020 18:33:19 +0300 Subject: [PATCH] refactor: add @expo/dev-server (#1845) Co-authored-by: Evan Bacon --- .github/workflows/test.yml | 5 +- .../ts-declarations/metro-config/index.d.ts | 23 +- .../ts-declarations/metro/index.d.ts | 364 ++++++++++- .../index.d.ts | 33 + packages/dev-server/.gitignore | 2 + packages/dev-server/LICENSE | 21 + packages/dev-server/README.md | 5 + packages/dev-server/babel.config.js | 11 + packages/dev-server/package.json | 60 ++ packages/dev-server/src/LogReporter.ts | 18 + packages/dev-server/src/MetroDevServer.ts | 45 ++ .../clientLogsMiddleware-test.ts.snap | 8 + .../__tests__/clientLogsMiddleware-test.ts | 115 ++++ .../src/middleware/clientLogsMiddleware.ts | 93 +++ packages/dev-server/tsconfig.json | 8 + packages/metro-config/package.json | 3 +- packages/metro-config/src/ExpoMetroConfig.ts | 6 +- .../src/__tests__/ExpoMetroConfig-test.ts | 2 +- .../ExpoMetroConfig-test.ts.snap | 4 +- packages/xdl/package.json | 1 + packages/xdl/src/Project.ts | 123 ++-- yarn.lock | 592 +++++++++++++++++- 22 files changed, 1480 insertions(+), 62 deletions(-) create mode 100644 packages/babel-preset-cli/ts-declarations/react-native-community__cli-server-api/index.d.ts create mode 100644 packages/dev-server/.gitignore create mode 100644 packages/dev-server/LICENSE create mode 100644 packages/dev-server/README.md create mode 100644 packages/dev-server/babel.config.js create mode 100644 packages/dev-server/package.json create mode 100644 packages/dev-server/src/LogReporter.ts create mode 100644 packages/dev-server/src/MetroDevServer.ts create mode 100644 packages/dev-server/src/middleware/__tests__/__snapshots__/clientLogsMiddleware-test.ts.snap create mode 100644 packages/dev-server/src/middleware/__tests__/clientLogsMiddleware-test.ts create mode 100644 packages/dev-server/src/middleware/clientLogsMiddleware.ts create mode 100644 packages/dev-server/tsconfig.json diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 47d35d8f16..de1cdb8aff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/cache@v1 id: cache-build with: - path: '.' + path: "." key: ${{ github.sha }} test: runs-on: ubuntu-latest @@ -29,6 +29,7 @@ jobs: [ babel-preset-cli, config, + dev-server, expo-cli, expo-codemod, json-file, @@ -46,7 +47,7 @@ jobs: - uses: actions/cache@v1 id: restore-build with: - path: '.' + path: "." key: ${{ github.sha }} - name: Coverage ${{ matrix.package }} run: cd packages/${{ matrix.package }} && yarn test --coverage diff --git a/packages/babel-preset-cli/ts-declarations/metro-config/index.d.ts b/packages/babel-preset-cli/ts-declarations/metro-config/index.d.ts index c2d9581413..398c038e3e 100644 --- a/packages/babel-preset-cli/ts-declarations/metro-config/index.d.ts +++ b/packages/babel-preset-cli/ts-declarations/metro-config/index.d.ts @@ -1,6 +1,16 @@ declare module 'metro-config' { import { IncomingMessage, ServerResponse } from 'http'; - import { JsTransformerConfig, Reporter } from 'metro'; + import { + DeltaResult, + Graph, + Module, + SerializerOptions, + JsTransformerConfig, + Reporter, + TransformResult, + Server, + TransformVariants, + } from 'metro'; // TODO: import { CacheStore } from 'metro-cache'; type CacheStore = unknown; @@ -9,17 +19,6 @@ declare module 'metro-config' { // TODO: import { BasicSourceMap, MixedSourceMap } from 'metro-source-map'; type BasicSourceMap = unknown; type MixedSourceMap = unknown; - // TODO: import { DeltaResult, Graph, Module, SerializerOptions } from 'metro/src/DeltaBundler/types'; - type DeltaResult = unknown; - type Graph = unknown; - type Module = unknown; - type SerializerOptions = unknown; - // TODO: import { TransformResult } from 'metro/src/DeltaBundler'; - type TransformResult = unknown; - // TODO: import { TransformVariants } from 'metro/src/ModuleGraph/types'; - type TransformVariants = unknown; - // TODO: import Server from 'metro/src/Server'; - type Server = unknown; //#region metro/packages/metro-config/src/configTypes.flow.js diff --git a/packages/babel-preset-cli/ts-declarations/metro/index.d.ts b/packages/babel-preset-cli/ts-declarations/metro/index.d.ts index 660d00fb0d..71de59eb76 100644 --- a/packages/babel-preset-cli/ts-declarations/metro/index.d.ts +++ b/packages/babel-preset-cli/ts-declarations/metro/index.d.ts @@ -1,5 +1,229 @@ declare module 'metro' { - //#region metro/packages/metro/src/JSTransformer/worker.js + //#region metro/src/Assets.js + + type AssetDataWithoutFiles = { + readonly __packager_asset: boolean; + readonly fileSystemLocation: string; + readonly hash: string; + readonly height: number | null | undefined; + readonly httpServerLocation: string; + readonly name: string; + readonly scales: Array; + readonly type: string; + readonly width: number | null | undefined; + }; + + type AssetData = AssetDataWithoutFiles & { readonly files: Array }; + + //#endregion + //#region metro/src/DeltaBundler/types.flow.js + + interface MixedOutput { + readonly data: unknown; + readonly type: string; + } + + interface BabelSourceLocation { + start: { line: number; column: number }; + end: { line: number; column: number }; + identifierName?: string; + } + + interface TransformResultDependency { + /** + * The literal name provided to a require or import call. For example 'foo' in + * case of `require('foo')`. + */ + readonly name: string; + + /** + * Extra data returned by the dependency extractor. Whatever is added here is + * blindly piped by Metro to the serializers. + */ + readonly data: { + /** + * If `true` this dependency is due to a dynamic `import()` call. If `false`, + * this dependency was pulled using a synchronous `require()` call. + */ + readonly isAsync: boolean; + + /** + * The dependency is actually a `__prefetchImport()` call. + */ + readonly isPrefetchOnly?: true; + + /** + * The condition for splitting on this dependency edge. + */ + readonly splitCondition?: { + readonly mobileConfigName: string; + }; + + /** + * The dependency is enclosed in a try/catch block. + */ + readonly isOptional?: boolean; + + readonly locs: ReadonlyArray; + }; + } + + interface Dependency { + readonly absolutePath: string; + readonly data: TransformResultDependency; + } + + export interface Module { + readonly dependencies: Map; + readonly inverseDependencies: Set; + readonly output: ReadonlyArray; + readonly path: string; + readonly getSource: () => Buffer; + } + + export interface Graph { + dependencies: Map>; + importBundleNames: Set; + readonly entryPoints: ReadonlyArray; + } + + export type TransformResult = Readonly<{ + dependencies: ReadonlyArray; + output: ReadonlyArray; + }>; + + interface AllowOptionalDependenciesWithOptions { + readonly exclude: Array; + } + type AllowOptionalDependencies = boolean | AllowOptionalDependenciesWithOptions; + + export interface DeltaResult { + readonly added: Map>; + readonly modified: Map>; + readonly deleted: Set; + readonly reset: boolean; + } + + export interface SerializerOptions { + readonly asyncRequireModulePath: string; + readonly createModuleId: (arg0: string) => number; + readonly dev: boolean; + readonly getRunModuleStatement: (arg0: number | string) => string; + readonly inlineSourceMap: boolean | null | undefined; + readonly modulesOnly: boolean; + readonly processModuleFilter: (module: Module) => boolean; + readonly projectRoot: string; + readonly runBeforeMainModule: ReadonlyArray; + readonly runModule: boolean; + readonly sourceMapUrl: string | null | undefined; + readonly sourceUrl: string | null | undefined; + } + + //#endregion + //#region metro/src/DeltaBundler/Serializers/getRamBundleInfo.js + + interface RamBundleInfo { + getDependencies: (filePath: string) => Set; + startupModules: ReadonlyArray; + lazyModules: ReadonlyArray; + groups: Map>; + } + + //#endregion + //#region metro/src/index.js + + import { Server as HttpServer } from 'http'; + import { Server as HttpsServer } from 'https'; + import { loadConfig, ConfigT, InputConfigT, Middleware } from 'metro-config'; + + type MetroMiddleWare = { + attachHmrServer: (httpServer: HttpServer | HttpsServer) => void; + end: () => void; + metroServer: Server; + middleware: Middleware; + }; + + type RunServerOptions = { + hasReducedPerformance?: boolean; + hmrEnabled?: boolean; + host?: string; + onError?: (arg0: Error & { code?: string }) => void; + onReady?: (server: HttpServer | HttpsServer) => void; + runInspectorProxy?: boolean; + secure?: boolean; + secureCert?: string; + secureKey?: string; + }; + + type BuildGraphOptions = { + entries: ReadonlyArray; + customTransformOptions?: CustomTransformOptions; + dev?: boolean; + minify?: boolean; + onProgress?: (transformedFileCount: number, totalFileCount: number) => void; + platform?: string; + type?: 'module' | 'script'; + }; + + type RunBuildOptions = { + entry: string; + dev?: boolean; + out?: string; + onBegin?: () => void; + onComplete?: () => void; + onProgress?: (transformedFileCount: number, totalFileCount: number) => void; + minify?: boolean; + output?: { + build: ( + arg0: Server, + arg1: RequestOptions + ) => Promise<{ + code: string; + map: string; + }>; + save: ( + arg0: { + code: string; + map: string; + }, + arg1: OutputOptions, + arg2: (...args: Array) => void + ) => Promise; + }; + platform?: string; + sourceMap?: boolean; + sourceMapUrl?: string; + }; + + export function runMetro(config: InputConfigT, options?: ServerOptions): Promise; + + export { loadConfig }; + + export function createConnectMiddleware( + config: ConfigT, + options?: ServerOptions + ): Promise; + + export function runServer( + config: ConfigT, + options: RunServerOptions + ): Promise; + + export function runBuild( + config: ConfigT, + options: RunBuildOptions + ): Promise<{ + code: string; + map: string; + }>; + + export function buildGraph(config: InputConfigT, options: BuildGraphOptions): Promise; + //#endregion + //#region metro/src/JSTransformer/worker.js + + type CustomTransformOptions = { + [key: string]: unknown; + }; export type JsTransformerConfig = Readonly<{ assetPlugins: ReadonlyArray; @@ -18,7 +242,7 @@ declare module 'metro' { }>; //#endregion - //#region metro/packages/metro/src/lib/reporting.js + //#region metro/src/lib/reporting.js /** * A tagged union of all the actions that may happen and we may want to @@ -120,5 +344,141 @@ declare module 'metro' { update(event: ReportableEvent): void; } + //#endregion + //#region metro/src/ModuleGraph/types.flow.js + + export type TransformVariants = { + readonly [name: string]: {}; + }; + + //#endregion + //#region metro/src/Server.js + + type ServerOptions = Readonly<{ + watch?: boolean; + }>; + + //#endregion + //#region metro/src/Server/index.js + + import { IncomingMessage, ServerResponse } from 'http'; + + // TODO: type declaration + type IncrementalBundler = unknown; + + export class Server { + constructor(config: ConfigT, options?: ServerOptions); + + end(): void; + + getBundler(): IncrementalBundler; + + getCreateModuleId(): (path: string) => number; + + build( + options: BundleOptions + ): Promise<{ + code: string; + map: string; + }>; + + getRamBundleInfo(options: BundleOptions): Promise; + + getAssets(options: BundleOptions): Promise>; + + getOrderedDependencyPaths(options: { + readonly dev: boolean; + readonly entryFile: string; + readonly minify: boolean; + readonly platform: string; + }): Promise>; + + processRequest( + req: IncomingMessage, + res: ServerResponse, + next: (arg0: Error | null | undefined) => unknown + ): void; + + getNewBuildID(): string; + + getPlatforms(): ReadonlyArray; + + getWatchFolders(): ReadonlyArray; + + static DEFAULT_GRAPH_OPTIONS: { + customTransformOptions: any; + dev: boolean; + hot: boolean; + minify: boolean; + }; + + static DEFAULT_BUNDLE_OPTIONS: typeof Server.DEFAULT_GRAPH_OPTIONS & { + excludeSource: false; + inlineSourceMap: false; + modulesOnly: false; + onProgress: null; + runModule: true; + shallow: false; + sourceMapUrl: null; + sourceUrl: null; + }; + } + + //#endregion + //#region metro/src/shared/types.flow.js + + type BundleType = 'bundle' | 'delta' | 'meta' | 'map' | 'ram' | 'cli' | 'hmr' | 'todo' | 'graph'; + + type MetroSourceMapOrMappings = MixedSourceMap | Array; + + type BundleOptions = { + bundleType: BundleType; + customTransformOptions: CustomTransformOptions; + dev: boolean; + entryFile: string; + readonly excludeSource: boolean; + readonly hot: boolean; + readonly inlineSourceMap: boolean; + minify: boolean; + readonly modulesOnly: boolean; + onProgress: (doneCont: number, totalCount: number) => unknown | null | undefined; + readonly platform: string | null | undefined; + readonly runModule: boolean; + readonly shallow: boolean; + sourceMapUrl: string | null | undefined; + sourceUrl: string | null | undefined; + createModuleIdFactory?: () => (path: string) => number; + }; + + type ModuleTransportLike = { + readonly code: string; + readonly id: number; + readonly map: MetroSourceMapOrMappings | null | undefined; + readonly name?: string; + readonly sourcePath: string; + }; + + type OutputOptions = { + bundleOutput: string; + bundleEncoding?: 'utf8' | 'utf16le' | 'ascii'; + dev?: boolean; + indexedRamBundle?: boolean; + platform: string; + sourcemapOutput?: string; + sourcemapSourcesRoot?: string; + sourcemapUseAbsolutePath?: boolean; + }; + + type RequestOptions = { + entryFile: string; + inlineSourceMap?: boolean; + sourceMapUrl?: string; + dev?: boolean; + minify: boolean; + platform: string; + createModuleIdFactory?: () => (path: string) => number; + onProgress?: (transformedFileCount: number, totalFileCount: number) => void; + }; + //#endregion } diff --git a/packages/babel-preset-cli/ts-declarations/react-native-community__cli-server-api/index.d.ts b/packages/babel-preset-cli/ts-declarations/react-native-community__cli-server-api/index.d.ts new file mode 100644 index 0000000000..0286e5bbd6 --- /dev/null +++ b/packages/babel-preset-cli/ts-declarations/react-native-community__cli-server-api/index.d.ts @@ -0,0 +1,33 @@ +/// +/// +declare module '@react-native-community/cli-server-api' { + import http from 'http'; + import { Server as HttpsServer } from 'https'; + + type MiddlewareOptions = { + host?: string; + watchFolders: ReadonlyArray; + port: number; + }; + + export function createDevServerMiddleware( + options: MiddlewareOptions + ): { + attachToServer( + server: http.Server | HttpsServer + ): { + debuggerProxy: { + server: import('ws').Server; + isDebuggerConnected(): boolean; + }; + eventsSocket: { + reportEvent: (event: any) => void; + }; + messageSocket: { + broadcast: (method: string, params?: Record | undefined) => void; + }; + }; + middleware: any; + }; + //# sourceMappingURL=index.d.ts.map +} diff --git a/packages/dev-server/.gitignore b/packages/dev-server/.gitignore new file mode 100644 index 0000000000..dd87e2d73f --- /dev/null +++ b/packages/dev-server/.gitignore @@ -0,0 +1,2 @@ +node_modules +build diff --git a/packages/dev-server/LICENSE b/packages/dev-server/LICENSE new file mode 100644 index 0000000000..1562b6cb16 --- /dev/null +++ b/packages/dev-server/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020-present 650 Industries, Inc. (aka Expo) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/dev-server/README.md b/packages/dev-server/README.md new file mode 100644 index 0000000000..8f8a582f86 --- /dev/null +++ b/packages/dev-server/README.md @@ -0,0 +1,5 @@ +# dev-server + +A React Native development server. + +This package is used by Expo CLI to run a development server for React Native apps. It is built on [Metro](https://facebook.github.io/metro/) (a JavaScript bundler) and [`@react-native-community/cli-server-api`](https://github.com/react-native-community/cli/tree/master/packages/cli-server-api) (the HTTP and WebSocket API for React Native apps to interface with the development server). diff --git a/packages/dev-server/babel.config.js b/packages/dev-server/babel.config.js new file mode 100644 index 0000000000..5148112ffc --- /dev/null +++ b/packages/dev-server/babel.config.js @@ -0,0 +1,11 @@ +module.exports = function(api) { + api.cache(true); + return { + // Only use this when running tests + env: { + test: { + presets: ['@expo/babel-preset-cli'], + }, + }, + }; +}; diff --git a/packages/dev-server/package.json b/packages/dev-server/package.json new file mode 100644 index 0000000000..3dc9c69458 --- /dev/null +++ b/packages/dev-server/package.json @@ -0,0 +1,60 @@ +{ + "name": "@expo/dev-server", + "version": "0.0.0", + "description": "Development servers for starting React Native projects", + "main": "build/MetroDevServer.js", + "scripts": { + "watch": "tsc --watch", + "build": "tsc", + "prepare": "yarn run clean && yarn build", + "clean": "rm -rf build ./tsconfig.tsbuildinfo", + "lint": "eslint .", + "test": "jest" + }, + "jest": { + "testEnvironment": "node", + "roots": [ + "src" + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/expo/expo-cli.git", + "directory": "packages/dev-server" + }, + "keywords": [ + "json", + "react-native", + "expo", + "react", + "metro", + "dev-server", + "bundler" + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/expo/expo-cli/issues" + }, + "homepage": "https://github.com/expo/expo-cli/tree/master/packages/dev-server#readme", + "files": [ + "build", + "!*/__tests__/*" + ], + "dependencies": { + "@expo/bunyan": "3.0.2", + "@expo/config": "3.1.4", + "@expo/metro-config": "0.0.9", + "@react-native-community/cli-server-api": "4.8.0", + "body-parser": "1.19.0", + "serialize-error": "6.0.0" + }, + "devDependencies": { + "@expo/babel-preset-cli": "^0.2.1", + "@types/connect": "^3.4.33", + "jest": "^25.3.0", + "node-fetch": "^2.6.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/dev-server/src/LogReporter.ts b/packages/dev-server/src/LogReporter.ts new file mode 100644 index 0000000000..b06cdf7f36 --- /dev/null +++ b/packages/dev-server/src/LogReporter.ts @@ -0,0 +1,18 @@ +import Log from '@expo/bunyan'; +import { serializeError } from 'serialize-error'; + +export default class LogReporter { + constructor(public logger: Log, public reportEvent: (event: any) => void = () => {}) { + this.logger = logger; + this.reportEvent = reportEvent; + } + + update(event: any) { + if (event.error instanceof Error) { + event.error = serializeError(event.error); + } + // TODO(ville): replace xdl.PackagerLogsStream with a reporter to avoid serializing to JSON. + this.logger.info({ tag: 'metro' }, JSON.stringify(event)); + this.reportEvent(event); + } +} diff --git a/packages/dev-server/src/MetroDevServer.ts b/packages/dev-server/src/MetroDevServer.ts new file mode 100644 index 0000000000..1ec0b82d81 --- /dev/null +++ b/packages/dev-server/src/MetroDevServer.ts @@ -0,0 +1,45 @@ +import { getConfig, resolveModule } from '@expo/config'; +import { createDevServerMiddleware } from '@react-native-community/cli-server-api'; +import Log from '@expo/bunyan'; +import * as ExpoMetroConfig from '@expo/metro-config'; +import bodyParser from 'body-parser'; + +import clientLogsMiddleware from './middleware/clientLogsMiddleware'; +import LogReporter from './LogReporter'; + +export type MetroDevServerOptions = ExpoMetroConfig.LoadOptions & { logger: Log }; + +export async function runMetroDevServerAsync(projectRoot: string, options: MetroDevServerOptions) { + const { exp } = getConfig(projectRoot, { skipSDKVersionRequirement: true }); + const Metro = require(resolveModule('metro', projectRoot, exp)); + + const reporter = new LogReporter(options.logger); + + const metroConfig = await ExpoMetroConfig.loadAsync(projectRoot, { reporter, ...options }); + + const { middleware, attachToServer } = createDevServerMiddleware({ + port: metroConfig.server.port, + watchFolders: [...metroConfig.watchFolders], + }); + middleware.use(bodyParser.json()); + middleware.use('/logs', clientLogsMiddleware(options.logger)); + + const customEnhanceMiddleware = metroConfig.server.enhanceMiddleware; + // @ts-ignore can't mutate readonly config + metroConfig.server.enhanceMiddleware = (metroMiddleware: any, server: Metro.Server) => { + if (customEnhanceMiddleware) { + metroMiddleware = customEnhanceMiddleware(metroMiddleware, server); + } + return middleware.use(metroMiddleware); + }; + + const serverInstance = await Metro.runServer(metroConfig, { hmrEnabled: true }); + + const { eventsSocket } = attachToServer(serverInstance); + reporter.reportEvent = eventsSocket.reportEvent; + + return { + server: serverInstance, + middleware, + }; +} diff --git a/packages/dev-server/src/middleware/__tests__/__snapshots__/clientLogsMiddleware-test.ts.snap b/packages/dev-server/src/middleware/__tests__/__snapshots__/clientLogsMiddleware-test.ts.snap new file mode 100644 index 0000000000..27c52ea36c --- /dev/null +++ b/packages/dev-server/src/middleware/__tests__/__snapshots__/clientLogsMiddleware-test.ts.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`logs messages from the device 1`] = ` +Array [ + "iPhone: [info] Hello world!", + "iPhone: [error] Something went wrong...", +] +`; diff --git a/packages/dev-server/src/middleware/__tests__/clientLogsMiddleware-test.ts b/packages/dev-server/src/middleware/__tests__/clientLogsMiddleware-test.ts new file mode 100644 index 0000000000..617f8fe189 --- /dev/null +++ b/packages/dev-server/src/middleware/__tests__/clientLogsMiddleware-test.ts @@ -0,0 +1,115 @@ +import http from 'http'; + +import bodyParser from 'body-parser'; +import bunyan from '@expo/bunyan'; +import connect from 'connect'; +import fetch from 'node-fetch'; + +import clientLogsMiddleware from '../clientLogsMiddleware'; + +const headers = { + 'content-type': 'application/json', + 'device-id': '11111111-CAFE-0000-0000-111111111111', + 'session-id': '22222222-C0DE-0000-0000-222222222222', + 'device-name': 'iPhone', +}; + +it('logs messages from the device', async () => { + const { server, url, logStream } = await createServerAsync(); + try { + const response = await fetch(`${url}/logs`, { + method: 'POST', + headers, + body: JSON.stringify([ + { + count: 1, + level: 'info', + body: ['Hello world!'], + includesStack: false, + groupDepth: 0, + }, + { + count: 2, + level: 'error', + body: [ + { + message: 'Something went wrong...', + stack: 'App.js:3:12 in ', + }, + ], + includesStack: true, + groupDepth: 0, + }, + { + // We want this to be filtered out. + count: 3, + level: 'info', + body: [ + 'BugReporting extraData:', + 'Object {\n' + + ' "AppRegistry.runApplication1": "Running \\"main\\" with yada yada yada",\n' + + '}', + ], + includesStack: false, + groupDepth: 0, + }, + ]), + }); + expect(response.ok).toBe(true); + expect(logStream.output).toMatchSnapshot(); + } finally { + server.close(); + } +}); + +class TestLogStream { + output: string[] = []; + + write(record: any) { + const message = record.includesStack ? JSON.parse(record.msg).message : record.msg; + const deviceName = record.deviceName ?? ''; + if (record.level < bunyan.INFO) { + this.output.push(`${deviceName}: [debug] ${message}`); + } else if (record.level < bunyan.WARN) { + this.output.push(`${deviceName}: [info] ${message}`); + } else if (record.level < bunyan.ERROR) { + this.output.push(`${deviceName}: [warn] ${message}`); + } else { + this.output.push(`${deviceName}: [error] ${message}`); + } + } +} + +async function createServerAsync() { + const logStream = new TestLogStream(); + const logger = bunyan.createLogger({ + name: 'expo-test', + streams: [ + { + type: 'raw', + stream: logStream, + level: 'info', + }, + ], + }); + const app = connect() + .use(bodyParser.json()) + .use(clientLogsMiddleware(logger)); + + const server = http.createServer(app); + await new Promise((resolve, reject) => + server.listen((error: any) => { + if (error) reject(error); + else resolve(); + }) + ); + + const address = server.address(); + if (!address || typeof address === 'string') throw new Error('server has no port'); + + return { + server, + url: `http://localhost:${address.port}`, + logStream, + }; +} diff --git a/packages/dev-server/src/middleware/clientLogsMiddleware.ts b/packages/dev-server/src/middleware/clientLogsMiddleware.ts new file mode 100644 index 0000000000..087de444e6 --- /dev/null +++ b/packages/dev-server/src/middleware/clientLogsMiddleware.ts @@ -0,0 +1,93 @@ +import http from 'http'; +import { HandleFunction } from 'connect'; +import Log from '@expo/bunyan'; + +type ConsoleLogLevel = 'info' | 'warn' | 'error' | 'debug'; + +export default function clientLogsMiddleware(logger: Log): HandleFunction { + return function( + req: http.IncomingMessage & { body?: any }, + res: http.ServerResponse, + next: (err?: Error) => void + ) { + try { + const deviceId = req.headers['device-id']; + const deviceName = req.headers['device-name']; + if (!deviceId) { + res.writeHead(400).end('Missing Device-Id.'); + return; + } + if (!deviceName) { + res.writeHead(400).end('Missing Device-Name.'); + return; + } + if (!req.body) { + res.writeHead(400).end('Missing request body.'); + return; + } + handleDeviceLogs(logger, deviceId.toString(), deviceName.toString(), req.body); + } catch (error) { + logger.error({ tag: 'expo' }, `Error getting device logs: ${error} ${error.stack}`); + next(error); + } + res.end('Success'); + }; +} + +function isIgnorableBugReportingExtraData(body: any[]): boolean { + return body.length === 2 && body[0] === 'BugReporting extraData:'; +} + +function isAppRegistryStartupMessage(body: any[]): boolean { + return ( + body.length === 1 && + (/^Running application "main" with appParams:/.test(body[0]) || + /^Running "main" with \{/.test(body[0])) + ); +} + +function handleDeviceLogs(logger: Log, deviceId: string, deviceName: string, logs: any): void { + for (const log of logs) { + let body = Array.isArray(log.body) ? log.body : [log.body]; + let { level } = log; + + if (isIgnorableBugReportingExtraData(body)) { + level = 'debug'; + } + if (isAppRegistryStartupMessage(body)) { + body = [`Running application on ${deviceName}.`]; + } + + const args = body.map((obj: any) => { + if (typeof obj === 'undefined') { + return 'undefined'; + } + if (obj === 'null') { + return 'null'; + } + if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') { + return obj; + } + try { + return JSON.stringify(obj); + } catch (e) { + return obj.toString(); + } + }); + const logLevel = + level === 'info' || level === 'warn' || level === 'error' || level === 'debug' + ? (level as ConsoleLogLevel) + : 'info'; + logger[logLevel]( + { + tag: 'device', + deviceId, + deviceName, + groupDepth: log.groupDepth, + shouldHide: log.shouldHide, + includesStack: log.includesStack, + }, + ...args + ); + } +} diff --git a/packages/dev-server/tsconfig.json b/packages/dev-server/tsconfig.json new file mode 100644 index 0000000000..609ef77c44 --- /dev/null +++ b/packages/dev-server/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@expo/babel-preset-cli/tsconfig.base", + "include": ["src/**/*.ts"], + "compilerOptions": { + "outDir": "build", + "rootDir": "src" + } +} diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index ddf22adfed..16ad76dce3 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -34,7 +34,8 @@ "transformer.js" ], "dependencies": { - "@expo/config": "3.1.4" + "@expo/config": "3.1.4", + "metro-react-native-babel-transformer": "^0.58.0" }, "peerDependencies": { "metro": "^0.56.0", diff --git a/packages/metro-config/src/ExpoMetroConfig.ts b/packages/metro-config/src/ExpoMetroConfig.ts index 54304308c2..551176326e 100644 --- a/packages/metro-config/src/ExpoMetroConfig.ts +++ b/packages/metro-config/src/ExpoMetroConfig.ts @@ -27,7 +27,9 @@ export function getDefaultConfig( options: DefaultConfigOptions = {} ): InputConfigT { const { exp } = getConfig(projectRoot, { skipSDKVersionRequirement: true }); - const reactNativePath = resolveModule('react-native', projectRoot, exp); + const reactNativePath = path.dirname( + resolveModule('react-native/package.json', projectRoot, exp) + ); const target = options.target ?? process.env.EXPO_TARGET ?? getDefaultTarget(projectRoot); if (!(target === 'managed' || target === 'bare')) { @@ -69,7 +71,7 @@ export function getDefaultConfig( }, }, transformer: { - babelTransformerPath: require.resolve('../transformer'), + babelTransformerPath: require.resolve('metro-react-native-babel-transformer'), // TODO: Bacon: Add path for web platform assetRegistryPath: path.join(reactNativePath, 'Libraries/Image/AssetRegistry'), assetPlugins: [resolveModule('expo/tools/hashAssetFiles', projectRoot, exp)], diff --git a/packages/metro-config/src/__tests__/ExpoMetroConfig-test.ts b/packages/metro-config/src/__tests__/ExpoMetroConfig-test.ts index c624db6d7b..1852278f90 100644 --- a/packages/metro-config/src/__tests__/ExpoMetroConfig-test.ts +++ b/packages/metro-config/src/__tests__/ExpoMetroConfig-test.ts @@ -9,7 +9,7 @@ describe('getDefaultConfig', () => { transformer: { assetPlugins: expect.arrayContaining([expect.stringContaining('hashAssetFiles')]), assetRegistryPath: expect.stringContaining('AssetRegistry'), - babelTransformerPath: expect.stringContaining('transformer.js'), + babelTransformerPath: expect.stringContaining('metro-react-native-babel-transformer'), }, }; diff --git a/packages/metro-config/src/__tests__/__snapshots__/ExpoMetroConfig-test.ts.snap b/packages/metro-config/src/__tests__/__snapshots__/ExpoMetroConfig-test.ts.snap index c29b8a92b4..7b9cea1150 100644 --- a/packages/metro-config/src/__tests__/__snapshots__/ExpoMetroConfig-test.ts.snap +++ b/packages/metro-config/src/__tests__/__snapshots__/ExpoMetroConfig-test.ts.snap @@ -47,7 +47,7 @@ Object { StringContaining "hashAssetFiles", ], "assetRegistryPath": StringContaining "AssetRegistry", - "babelTransformerPath": StringContaining "transformer.js", + "babelTransformerPath": StringContaining "metro-react-native-babel-transformer", }, } `; @@ -86,7 +86,7 @@ Object { StringContaining "hashAssetFiles", ], "assetRegistryPath": StringContaining "AssetRegistry", - "babelTransformerPath": StringContaining "transformer.js", + "babelTransformerPath": StringContaining "metro-react-native-babel-transformer", }, } `; diff --git a/packages/xdl/package.json b/packages/xdl/package.json index f2b080dde5..5d43b0e68f 100644 --- a/packages/xdl/package.json +++ b/packages/xdl/package.json @@ -32,6 +32,7 @@ "dependencies": { "@expo/bunyan": "3.0.2", "@expo/config": "3.1.4", + "@expo/dev-server": "0.0.0", "@expo/json-file": "8.2.12", "@expo/ngrok": "2.4.3", "@expo/osascript": "2.0.15", diff --git a/packages/xdl/src/Project.ts b/packages/xdl/src/Project.ts index 7ad8f6a904..77dd54aa9e 100644 --- a/packages/xdl/src/Project.ts +++ b/packages/xdl/src/Project.ts @@ -12,6 +12,7 @@ import { import slug from 'slugify'; import { getBareExtensions, getManagedExtensions } from '@expo/config/paths'; +import { MetroDevServerOptions, runMetroDevServerAsync } from '@expo/dev-server'; import JsonFile from '@expo/json-file'; import ngrok from '@expo/ngrok'; import axios from 'axios'; @@ -22,6 +23,7 @@ import delayAsync from 'delay-async'; import express from 'express'; import freeportAsync from 'freeport-async'; import fs from 'fs-extra'; +import getenv from 'getenv'; import HashIds from 'hashids'; import joi from 'joi'; import chunk from 'lodash/chunk'; @@ -35,6 +37,8 @@ import minimatch from 'minimatch'; import { AddressInfo } from 'net'; import os from 'os'; import path from 'path'; +import http from 'http'; +import { URL } from 'url'; import readLastLines from 'read-last-lines'; import semver from 'semver'; import split from 'split'; @@ -1925,30 +1929,18 @@ function shouldExposeEnvironmentVariableInManifest(key: string) { return key.startsWith('REACT_NATIVE_') || key.startsWith('EXPO_'); } -export async function startExpoServerAsync(projectRoot: string): Promise { - _assertValidProjectRoot(projectRoot); - await stopExpoServerAsync(projectRoot); - let app = express(); - app.use( - express.json({ - limit: '10mb', - }) - ); - app.use( - express.urlencoded({ - limit: '10mb', - extended: true, - }) - ); - if ( - (ConnectionStatus.isOffline() - ? await Doctor.validateWithoutNetworkAsync(projectRoot) - : await Doctor.validateWithNetworkAsync(projectRoot)) === Doctor.FATAL - ) { - throw new Error(`Couldn't start project. Please fix the errors and restart the project.`); +function stripPort(host: string | undefined): string | undefined { + if (!host) { + return host; } - // Serve the manifest. - const manifestHandler = async (req: express.Request, res: express.Response) => { + return new URL('/', `http://${host}`).hostname; +} + +function getManifestHandler(projectRoot: string) { + return async ( + req: express.Request | http.IncomingMessage, + res: express.Response | http.ServerResponse + ) => { try { // We intentionally don't `await`. We want to continue trying even // if there is a potential error in the package.json and don't want to slow @@ -1981,13 +1973,14 @@ export async function startExpoServerAsync(projectRoot: string): Promise { let path = `/${encodeURI(mainModuleName)}.bundle?platform=${encodeURIComponent( platform )}&${queryParams}`; + const hostname = stripPort(req.headers.host); manifest.bundleUrl = - (await UrlUtils.constructBundleUrlAsync(projectRoot, bundleUrlPackagerOpts, req.hostname)) + + (await UrlUtils.constructBundleUrlAsync(projectRoot, bundleUrlPackagerOpts, hostname)) + path; - manifest.debuggerHost = await UrlUtils.constructDebuggerHostAsync(projectRoot, req.hostname); + manifest.debuggerHost = await UrlUtils.constructDebuggerHostAsync(projectRoot, hostname); manifest.mainModuleName = mainModuleName; - manifest.logUrl = await UrlUtils.constructLogUrlAsync(projectRoot, req.hostname); - manifest.hostUri = await UrlUtils.constructHostUriAsync(projectRoot, req.hostname); + manifest.logUrl = await UrlUtils.constructLogUrlAsync(projectRoot, hostname); + manifest.hostUri = await UrlUtils.constructHostUriAsync(projectRoot, hostname); await _resolveManifestAssets( projectRoot, manifest as PublicConfig, @@ -2045,8 +2038,8 @@ export async function startExpoServerAsync(projectRoot: string): Promise { serverOS: os.platform(), serverOSVersion: os.release(), }; - res.append('Exponent-Server', JSON.stringify(hostInfo)); - res.send(manifestString); + res.setHeader('Exponent-Server', JSON.stringify(hostInfo)); + res.end(manifestString); Analytics.logEvent('Serve Manifest', { projectRoot, developerTool: Config.developerTool, @@ -2054,11 +2047,40 @@ export async function startExpoServerAsync(projectRoot: string): Promise { } catch (e) { ProjectUtils.logError(projectRoot, 'expo', e.stack); // 5xx = Server Error HTTP code - res.status(520).send({ - error: e.toString(), - }); + res.statusCode = 520; + res.end( + JSON.stringify({ + error: e.toString(), + }) + ); } }; +} + +export async function startExpoServerAsync(projectRoot: string): Promise { + _assertValidProjectRoot(projectRoot); + await stopExpoServerAsync(projectRoot); + let app = express(); + app.use( + express.json({ + limit: '10mb', + }) + ); + app.use( + express.urlencoded({ + limit: '10mb', + extended: true, + }) + ); + if ( + (ConnectionStatus.isOffline() + ? await Doctor.validateWithoutNetworkAsync(projectRoot) + : await Doctor.validateWithNetworkAsync(projectRoot)) === Doctor.FATAL + ) { + throw new Error(`Couldn't start project. Please fix the errors and restart the project.`); + } + // Serve the manifest. + const manifestHandler = getManifestHandler(projectRoot); app.get('/', manifestHandler); app.get('/manifest', manifestHandler); app.get('/index.exp', manifestHandler); @@ -2105,6 +2127,34 @@ export async function stopExpoServerAsync(projectRoot: string): Promise { }); } +async function startDevServerAsync(projectRoot: string, startOptions: StartOptions) { + _assertValidProjectRoot(projectRoot); + + const port = await _getFreePortAsync(19000); // Create packager options + await ProjectSettings.setPackagerInfoAsync(projectRoot, { + expoServerPort: port, + packagerPort: port, + }); + + const options: MetroDevServerOptions = { + port, + logger: ProjectUtils.getLogger(projectRoot), + }; + if (startOptions.reset) { + options.resetCache = true; + } + if (startOptions.maxWorkers != null) { + options.maxWorkers = startOptions.maxWorkers; + } + if (startOptions.target) { + // EXPO_TARGET is used by @expo/metro-config to determine the target when getDefaultConfig is + // called from metro.config.js and the --target option is used to override the default target. + process.env.EXPO_TARGET = options.target; + } + const { middleware } = await runMetroDevServerAsync(projectRoot, options); + middleware.use(getManifestHandler(projectRoot)); +} + async function _connectToNgrokAsync( projectRoot: string, args: ngrok.NgrokOptions, @@ -2335,17 +2385,14 @@ export async function startAsync( developerTool: Config.developerTool, }); - if (options.target) { - // EXPO_TARGET is used by @expo/metro-config to determine the target when getDefaultConfig is - // called from metro.config.js and the --target option is used to override the default target. - process.env.EXPO_TARGET = options.target; - } - let { exp } = getConfig(projectRoot); if (options.webOnly) { await Webpack.restartAsync(projectRoot, options); DevSession.startSession(projectRoot, exp, 'web'); return exp; + } else if (getenv.boolish('EXPO_USE_DEV_SERVER', false)) { + await startDevServerAsync(projectRoot, options); + DevSession.startSession(projectRoot, exp, 'native'); } else { await startExpoServerAsync(projectRoot); await startReactNativeServerAsync(projectRoot, options, verbose); diff --git a/yarn.lock b/yarn.lock index 69be5978db..aaf841d7c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -568,7 +568,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@^7.0.0": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz#47cf220d19d6d0d7b154304701f468fc1cc6ff46" + integrity sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== @@ -1586,6 +1593,16 @@ jest-util "^25.2.6" slash "^3.0.0" +"@jest/console@^25.3.0": + version "25.3.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-25.3.0.tgz#33b56b81238427bf3ebe3f7b3378d2f79cdbd409" + integrity sha512-LvSDNqpmZIZyweFaEQ6wKY7CbexPitlsLHGJtcooNECo0An/w49rFhjCJzu6efeb6+a3ee946xss1Jcd9r03UQ== + dependencies: + "@jest/source-map" "^25.2.6" + chalk "^3.0.0" + jest-util "^25.3.0" + slash "^3.0.0" + "@jest/core@^25.2.6": version "25.2.6" resolved "https://registry.yarnpkg.com/@jest/core/-/core-25.2.6.tgz#4bcb2919268d92c3813e1ff7c97443cde7a2873a" @@ -1620,6 +1637,40 @@ slash "^3.0.0" strip-ansi "^6.0.0" +"@jest/core@^25.3.0": + version "25.3.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-25.3.0.tgz#80f97a7a8b59dde741a24f30871cc26d0197d426" + integrity sha512-+D5a/tFf6pA/Gqft2DLBp/yeSRgXhlJ+Wpst0X/ZkfTRP54qDR3C61VfHwaex+GzZBiTcE9vQeoZ2v5T10+Mqw== + dependencies: + "@jest/console" "^25.3.0" + "@jest/reporters" "^25.3.0" + "@jest/test-result" "^25.3.0" + "@jest/transform" "^25.3.0" + "@jest/types" "^25.3.0" + ansi-escapes "^4.2.1" + chalk "^3.0.0" + exit "^0.1.2" + graceful-fs "^4.2.3" + jest-changed-files "^25.3.0" + jest-config "^25.3.0" + jest-haste-map "^25.3.0" + jest-message-util "^25.3.0" + jest-regex-util "^25.2.6" + jest-resolve "^25.3.0" + jest-resolve-dependencies "^25.3.0" + jest-runner "^25.3.0" + jest-runtime "^25.3.0" + jest-snapshot "^25.3.0" + jest-util "^25.3.0" + jest-validate "^25.3.0" + jest-watcher "^25.3.0" + micromatch "^4.0.2" + p-each-series "^2.1.0" + realpath-native "^2.0.0" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + "@jest/environment@^25.2.6": version "25.2.6" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-25.2.6.tgz#8f7931e79abd81893ce88b7306f0cc4744835000" @@ -1629,6 +1680,15 @@ "@jest/types" "^25.2.6" jest-mock "^25.2.6" +"@jest/environment@^25.3.0": + version "25.3.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-25.3.0.tgz#587f28ddb4b0dfe97404d3d4a4c9dbfa0245fb2e" + integrity sha512-vgooqwJTHLLak4fE+TaCGeYP7Tz1Y3CKOsNxR1sE0V3nx3KRUHn3NUnt+wbcfd5yQWKZQKAfW6wqbuwQLrXo3g== + dependencies: + "@jest/fake-timers" "^25.3.0" + "@jest/types" "^25.3.0" + jest-mock "^25.3.0" + "@jest/fake-timers@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93" @@ -1649,6 +1709,17 @@ jest-util "^25.2.6" lolex "^5.0.0" +"@jest/fake-timers@^25.3.0": + version "25.3.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-25.3.0.tgz#995aad36d5c8984165ca5db12e740ab8dbf7042a" + integrity sha512-NHAj7WbsyR3qBJPpBwSwqaq2WluIvUQsyzpJTN7XDVk7VnlC/y1BAnaYZL3vbPIP8Nhm0Ae5DJe0KExr/SdMJQ== + dependencies: + "@jest/types" "^25.3.0" + jest-message-util "^25.3.0" + jest-mock "^25.3.0" + jest-util "^25.3.0" + lolex "^5.0.0" + "@jest/reporters@^25.2.6": version "25.2.6" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-25.2.6.tgz#6d87e40fb15adb69e22bb83aa02a4d88b2253b5f" @@ -1680,6 +1751,37 @@ optionalDependencies: node-notifier "^6.0.0" +"@jest/reporters@^25.3.0": + version "25.3.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-25.3.0.tgz#7f39f0e6911561cc5112a1b54656de18faee269b" + integrity sha512-1u0ZBygs0C9DhdYgLCrRfZfNKQa+9+J7Uo+Z9z0RWLHzgsxhoG32lrmMOtUw48yR6bLNELdvzormwUqSk4H4Vg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^25.3.0" + "@jest/test-result" "^25.3.0" + "@jest/transform" "^25.3.0" + "@jest/types" "^25.3.0" + chalk "^3.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^25.3.0" + jest-resolve "^25.3.0" + jest-util "^25.3.0" + jest-worker "^25.2.6" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^3.1.0" + terminal-link "^2.0.0" + v8-to-istanbul "^4.0.1" + optionalDependencies: + node-notifier "^6.0.0" + "@jest/source-map@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" @@ -1717,6 +1819,16 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" +"@jest/test-result@^25.3.0": + version "25.3.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-25.3.0.tgz#137fab5e5c6fed36e5d40735d1eb029325e3bf06" + integrity sha512-mqrGuiiPXl1ap09Mydg4O782F3ouDQfsKqtQzIjitpwv3t1cHDwCto21jThw6WRRE+dKcWQvLG70GpyLJICfGw== + dependencies: + "@jest/console" "^25.3.0" + "@jest/types" "^25.3.0" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + "@jest/test-sequencer@^25.2.6": version "25.2.6" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-25.2.6.tgz#62026007610b0323e646ad70db59c69c7ed4785c" @@ -1727,6 +1839,16 @@ jest-runner "^25.2.6" jest-runtime "^25.2.6" +"@jest/test-sequencer@^25.3.0": + version "25.3.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-25.3.0.tgz#271ad5f2b8f8137d092ccedc87e16a50f8676209" + integrity sha512-Xvns3xbji7JCvVcDGvqJ/pf4IpmohPODumoPEZJ0/VgC5gI4XaNVIBET2Dq5Czu6Gk3xFcmhtthh/MBOTljdNg== + dependencies: + "@jest/test-result" "^25.3.0" + jest-haste-map "^25.3.0" + jest-runner "^25.3.0" + jest-runtime "^25.3.0" + "@jest/transform@^25.2.6", "@jest/transform@^25.3.0": version "25.3.0" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-25.3.0.tgz#083c5447d5307d9b9494d6968115b647460e71f1" @@ -2834,6 +2956,13 @@ dependencies: serve-static "^1.13.1" +"@react-native-community/cli-debugger-ui@^4.8.0": + version "4.8.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-4.8.0.tgz#9a6419b29be69422e0056bbb1874775750351d22" + integrity sha512-Eq9lHINDXiBAwmFRCMN8jeKk6FTDnTxAfITkjPUNNTj7q3K+fH/oyOMJjxbIZbryIJY6g+g/ln6vsS2WzISNYQ== + dependencies: + serve-static "^1.13.1" + "@react-native-community/cli-platform-android@^3.0.0-alpha.1": version "3.1.4" resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-3.1.4.tgz#61f964dc311623e60b0fb29c5f3732cc8a6f076f" @@ -2857,6 +2986,20 @@ js-yaml "^3.13.1" xcode "^2.0.0" +"@react-native-community/cli-server-api@4.8.0": + version "4.8.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-4.8.0.tgz#d66a14a8e3258f5e3ab3325acaa3b6783f1aab32" + integrity sha512-LqsxavpgqOhF+4wtQcl67c4kbPq8vI1SLE0zrs3WQv2HMwKlaWrEQobpkZdttJk59R5VMBzn0+HwOBDNsPoFSw== + dependencies: + "@react-native-community/cli-debugger-ui" "^4.8.0" + "@react-native-community/cli-tools" "^4.8.0" + compression "^1.7.1" + connect "^3.6.5" + errorhandler "^1.5.0" + pretty-format "^25.1.0" + serve-static "^1.13.1" + ws "^1.1.0" + "@react-native-community/cli-tools@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-3.0.0.tgz#fe48b80822ed7e49b8af051f9fe41e22a2a710b1" @@ -2867,6 +3010,18 @@ mime "^2.4.1" node-fetch "^2.5.0" +"@react-native-community/cli-tools@^4.8.0": + version "4.8.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-4.8.0.tgz#144a029c741c2cf40a7f9c059819ce9a69e7f1e3" + integrity sha512-voXGruhYyyhCbEYM2uZ54dMZcBgXFFcQxVK3nLwJDG9nSQGObZInj9Zf76ix5qGnvKKGWIGUcbmRhyLpAzTXuQ== + dependencies: + chalk "^3.0.0" + lodash "^4.17.15" + mime "^2.4.1" + node-fetch "^2.6.0" + open "^6.2.0" + shell-quote "1.6.1" + "@react-native-community/cli-types@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-3.0.0.tgz#488d46605cb05e88537e030f38da236eeda74652" @@ -3069,6 +3224,13 @@ dependencies: "@types/node" "*" +"@types/connect@^3.4.33": + version "3.4.33" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" + integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + dependencies: + "@types/node" "*" + "@types/copy-webpack-plugin@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@types/copy-webpack-plugin/-/copy-webpack-plugin-5.0.0.tgz#db7f9c9763b10b2af5c83f598fa9b5a13733b20b" @@ -5166,7 +5328,7 @@ babel-extract-comments@^1.0.0: dependencies: babylon "^6.18.0" -babel-jest@^25.2.0, babel-jest@^25.2.6: +babel-jest@^25.2.0, babel-jest@^25.2.6, babel-jest@^25.3.0: version "25.3.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-25.3.0.tgz#999d0c19e8427f66b796bf9ea233eedf087b957c" integrity sha512-qiXeX1Cmw4JZ5yQ4H57WpkO0MZ61Qj+YnsVUwAMnDV5ls+yHon11XjarDdgP7H8lTmiEi6biiZA8y3Tmvx6pCg== @@ -8931,6 +9093,18 @@ expect@^25.2.6: jest-message-util "^25.2.6" jest-regex-util "^25.2.6" +expect@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-25.3.0.tgz#5fd36e51befd05afb7184bc954f8a4792d184c71" + integrity sha512-buboTXML2h/L0Kh44Ys2Cx49mX20ISc5KDirkxIs3Q9AJv0kazweUAbukegr+nHDOvFRKmxdojjIHCjqAceYfg== + dependencies: + "@jest/types" "^25.3.0" + ansi-styles "^4.0.0" + jest-get-type "^25.2.6" + jest-matcher-utils "^25.3.0" + jest-message-util "^25.3.0" + jest-regex-util "^25.2.6" + expo-asset@~8.1.3: version "8.1.4" resolved "https://registry.yarnpkg.com/expo-asset/-/expo-asset-8.1.4.tgz#5265c28c1c279b2f9779269195bec4caf250ba5d" @@ -12046,6 +12220,14 @@ istanbul-reports@^3.0.0: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +istanbul-reports@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" + integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + iterall@1.2.2, iterall@^1.1.3, iterall@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7" @@ -12060,6 +12242,15 @@ jest-changed-files@^25.2.6: execa "^3.2.0" throat "^5.0.0" +jest-changed-files@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-25.3.0.tgz#85d8de6f4bd13dafda9d7f1e3f2565fc0e183c78" + integrity sha512-eqd5hyLbUjIVvLlJ3vQ/MoPxsxfESVXG9gvU19XXjKzxr+dXmZIqCXiY0OiYaibwlHZBJl2Vebkc0ADEMzCXew== + dependencies: + "@jest/types" "^25.3.0" + execa "^3.2.0" + throat "^5.0.0" + jest-cli@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-25.2.6.tgz#972356e70663e9b4faa07c507704441786e524e8" @@ -12079,6 +12270,25 @@ jest-cli@^25.2.6: realpath-native "^2.0.0" yargs "^15.3.1" +jest-cli@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-25.3.0.tgz#d9e11f5700cc5946583cf0d01a9bdebceed448d2" + integrity sha512-XpNQPlW1tzpP7RGG8dxpkRegYDuLjzSiENu92+CYM87nEbmEPb3b4+yo8xcsHOnj0AG7DUt9b3uG8LuHI3MDzw== + dependencies: + "@jest/core" "^25.3.0" + "@jest/test-result" "^25.3.0" + "@jest/types" "^25.3.0" + chalk "^3.0.0" + exit "^0.1.2" + import-local "^3.0.2" + is-ci "^2.0.0" + jest-config "^25.3.0" + jest-util "^25.3.0" + jest-validate "^25.3.0" + prompts "^2.0.1" + realpath-native "^2.0.0" + yargs "^15.3.1" + jest-config@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-25.2.6.tgz#fecff70f9fb083db1a25e7a624c3cd3035d01546" @@ -12103,6 +12313,30 @@ jest-config@^25.2.6: pretty-format "^25.2.6" realpath-native "^2.0.0" +jest-config@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-25.3.0.tgz#112b5e2f2e57dec4501dd2fe979044c06fb1317e" + integrity sha512-CmF1JnNWFmoCSPC4tnU52wnVBpuxHjilA40qH/03IHxIevkjUInSMwaDeE6ACfxMPTLidBGBCO3EbxvzPbo8wA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^25.3.0" + "@jest/types" "^25.3.0" + babel-jest "^25.3.0" + chalk "^3.0.0" + deepmerge "^4.2.2" + glob "^7.1.1" + jest-environment-jsdom "^25.3.0" + jest-environment-node "^25.3.0" + jest-get-type "^25.2.6" + jest-jasmine2 "^25.3.0" + jest-regex-util "^25.2.6" + jest-resolve "^25.3.0" + jest-util "^25.3.0" + jest-validate "^25.3.0" + micromatch "^4.0.2" + pretty-format "^25.3.0" + realpath-native "^2.0.0" + jest-dev-server@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/jest-dev-server/-/jest-dev-server-4.3.0.tgz#27c9cdc96d9f735bc90a309ca39305b76f2c0edd" @@ -12126,6 +12360,16 @@ jest-diff@^25.1.0, jest-diff@^25.2.6: jest-get-type "^25.2.6" pretty-format "^25.2.6" +jest-diff@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.3.0.tgz#0d7d6f5d6171e5dacde9e05be47b3615e147c26f" + integrity sha512-vyvs6RPoVdiwARwY4kqFWd4PirPLm2dmmkNzKqo38uZOzJvLee87yzDjIZLmY1SjM3XR5DwsUH+cdQ12vgqi1w== + dependencies: + chalk "^3.0.0" + diff-sequences "^25.2.6" + jest-get-type "^25.2.6" + pretty-format "^25.3.0" + jest-docblock@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-25.2.6.tgz#4b09f1e7b7d6b3f39242ef3647ac7106770f722b" @@ -12133,6 +12377,13 @@ jest-docblock@^25.2.6: dependencies: detect-newline "^3.0.0" +jest-docblock@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-25.3.0.tgz#8b777a27e3477cd77a168c05290c471a575623ef" + integrity sha512-aktF0kCar8+zxRHxQZwxMy70stc9R1mOmrLsT5VO3pIT0uzGRSDAXxSlz4NqQWpuLjPpuMhPRl7H+5FRsvIQAg== + dependencies: + detect-newline "^3.0.0" + jest-each@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-25.2.6.tgz#026f6dea2ccc443c35cea793265620aab1b278b6" @@ -12144,6 +12395,17 @@ jest-each@^25.2.6: jest-util "^25.2.6" pretty-format "^25.2.6" +jest-each@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-25.3.0.tgz#a319eecf1f6076164ab86f99ca166a55b96c0bd4" + integrity sha512-aBfS4VOf/Qs95yUlX6d6WBv0szvOcTkTTyCIaLuQGj4bSHsT+Wd9dDngVHrCe5uytxpN8VM+NAloI6nbPjXfXw== + dependencies: + "@jest/types" "^25.3.0" + chalk "^3.0.0" + jest-get-type "^25.2.6" + jest-util "^25.3.0" + pretty-format "^25.3.0" + jest-environment-jsdom@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-25.2.6.tgz#b7ae41c6035905b8e58d63a8f63cf8eaa00af279" @@ -12156,6 +12418,18 @@ jest-environment-jsdom@^25.2.6: jest-util "^25.2.6" jsdom "^15.2.1" +jest-environment-jsdom@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-25.3.0.tgz#c493ab8c41f28001520c70ef67dd88b88be6af05" + integrity sha512-jdE4bQN+k2QEZ9sWOxsqDJvMzbdFSCN/4tw8X0TQaCqyzKz58PyEf41oIr4WO7ERdp7WaJGBSUKF7imR3UW1lg== + dependencies: + "@jest/environment" "^25.3.0" + "@jest/fake-timers" "^25.3.0" + "@jest/types" "^25.3.0" + jest-mock "^25.3.0" + jest-util "^25.3.0" + jsdom "^15.2.1" + jest-environment-node@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-25.2.6.tgz#ad4398432867113f474d94fe37b071ed04b30f3d" @@ -12168,6 +12442,18 @@ jest-environment-node@^25.2.6: jest-util "^25.2.6" semver "^6.3.0" +jest-environment-node@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-25.3.0.tgz#9845f0e63991e8498448cb0ae804935689533db9" + integrity sha512-XO09S29Nx1NU7TiMPHMoDIkxoGBuKSTbE+sHp0gXbeLDXhIdhysUI25kOqFFSD9AuDgvPvxWCXrvNqiFsOH33g== + dependencies: + "@jest/environment" "^25.3.0" + "@jest/fake-timers" "^25.3.0" + "@jest/types" "^25.3.0" + jest-mock "^25.3.0" + jest-util "^25.3.0" + semver "^6.3.0" + jest-environment-puppeteer@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/jest-environment-puppeteer/-/jest-environment-puppeteer-4.3.0.tgz#49ac781c4b50459485af031cfb16ad1fd75d31ac" @@ -12249,6 +12535,29 @@ jest-jasmine2@^25.2.6: pretty-format "^25.2.6" throat "^5.0.0" +jest-jasmine2@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-25.3.0.tgz#16ae4f68adef65fb45001b26c864bcbcbf972830" + integrity sha512-NCYOGE6+HNzYFSui52SefgpsnIzvxjn6KAgqw66BdRp37xpMD/4kujDHLNW5bS5i53os5TcMn6jYrzQRO8VPrQ== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^25.3.0" + "@jest/source-map" "^25.2.6" + "@jest/test-result" "^25.3.0" + "@jest/types" "^25.3.0" + chalk "^3.0.0" + co "^4.6.0" + expect "^25.3.0" + is-generator-fn "^2.0.0" + jest-each "^25.3.0" + jest-matcher-utils "^25.3.0" + jest-message-util "^25.3.0" + jest-runtime "^25.3.0" + jest-snapshot "^25.3.0" + jest-util "^25.3.0" + pretty-format "^25.3.0" + throat "^5.0.0" + jest-leak-detector@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-25.2.6.tgz#68fbaf651142292b03e30641f33e15af9b8c62b1" @@ -12257,6 +12566,14 @@ jest-leak-detector@^25.2.6: jest-get-type "^25.2.6" pretty-format "^25.2.6" +jest-leak-detector@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-25.3.0.tgz#5b6bf04903b35be56038915a55f47291771f769f" + integrity sha512-jk7k24dMIfk8LUSQQGN8PyOy9+J0NAfHZWiDmUDYVMctY8FLJQ1eQ8+PjMoN8PgwhLIggUqgYJnyRFvUz3jLRw== + dependencies: + jest-get-type "^25.2.6" + pretty-format "^25.3.0" + jest-matcher-utils@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-25.2.6.tgz#a5156c1daa16e13ff6c55117f798b285a294a3e6" @@ -12267,6 +12584,16 @@ jest-matcher-utils@^25.2.6: jest-get-type "^25.2.6" pretty-format "^25.2.6" +jest-matcher-utils@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-25.3.0.tgz#76765788a26edaa8bc5f0100aea52ae383559648" + integrity sha512-ZBUJ2fchNIZt+fyzkuCFBb8SKaU//Rln45augfUtbHaGyVxCO++ANARdBK9oPGXU3hEDgyy7UHnOP/qNOJXFUg== + dependencies: + chalk "^3.0.0" + jest-diff "^25.3.0" + jest-get-type "^25.2.6" + pretty-format "^25.3.0" + jest-message-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" @@ -12294,6 +12621,19 @@ jest-message-util@^25.2.6: slash "^3.0.0" stack-utils "^1.0.1" +jest-message-util@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-25.3.0.tgz#e3836826fe5ca538a337b87d9bd2648190867f85" + integrity sha512-5QNy9Id4WxJbRITEbA1T1kem9bk7y2fD0updZMSTNHtbEDnYOGLDPAuFBhFgVmOZpv0n6OMdVkK+WhyXEPCcOw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/types" "^25.3.0" + "@types/stack-utils" "^1.0.1" + chalk "^3.0.0" + micromatch "^4.0.2" + slash "^3.0.0" + stack-utils "^1.0.1" + jest-mock@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" @@ -12308,6 +12648,13 @@ jest-mock@^25.2.6: dependencies: "@jest/types" "^25.2.6" +jest-mock@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-25.3.0.tgz#d72644509e40987a732a9a2534a1054f4649402c" + integrity sha512-yRn6GbuqB4j3aYu+Z1ezwRiZfp0o9om5uOcBovVtkcRLeBCNP5mT0ysdenUsxAHnQUgGwPOE1wwhtQYe6NKirQ== + dependencies: + "@jest/types" "^25.3.0" + jest-pnp-resolver@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" @@ -12335,6 +12682,15 @@ jest-resolve-dependencies@^25.2.6: jest-regex-util "^25.2.6" jest-snapshot "^25.2.6" +jest-resolve-dependencies@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-25.3.0.tgz#b0e4ae053dd44ddacc18c6ee12b5b7c28e445a90" + integrity sha512-bDUlLYmHW+f7J7KgcY2lkq8EMRqKonRl0XoD4Wp5SJkgAxKJnsaIOlrrVNTfXYf+YOu3VCjm/Ac2hPF2nfsCIA== + dependencies: + "@jest/types" "^25.3.0" + jest-regex-util "^25.2.6" + jest-snapshot "^25.3.0" + jest-resolve@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-25.2.6.tgz#84694ead5da13c2890ac04d4a78699ba937f3896" @@ -12347,6 +12703,18 @@ jest-resolve@^25.2.6: realpath-native "^2.0.0" resolve "^1.15.1" +jest-resolve@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-25.3.0.tgz#cb90a5bbea54a02eccdbbf4126a819595dcf91d6" + integrity sha512-IHoQAAybulsJ+ZgWis+ekYKDAoFkVH5Nx/znpb41zRtpxj4fr2WNV9iDqavdSm8GIpMlsfZxbC/fV9DhW0q9VQ== + dependencies: + "@jest/types" "^25.3.0" + browser-resolve "^1.11.3" + chalk "^3.0.0" + jest-pnp-resolver "^1.2.1" + realpath-native "^2.0.0" + resolve "^1.15.1" + jest-runner@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-25.2.6.tgz#5ee1607e66890ccd798695cfaa708e322087c50b" @@ -12372,6 +12740,31 @@ jest-runner@^25.2.6: source-map-support "^0.5.6" throat "^5.0.0" +jest-runner@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-25.3.0.tgz#673ef2ac79d2810eb6b2c1a3f82398375a3d1174" + integrity sha512-csDqSC9qGHYWDrzrElzEgFbteztFeZJmKhSgY5jlCIcN0+PhActzRNku0DA1Xa1HxGOb0/AfbP1EGJlP4fGPtA== + dependencies: + "@jest/console" "^25.3.0" + "@jest/environment" "^25.3.0" + "@jest/test-result" "^25.3.0" + "@jest/types" "^25.3.0" + chalk "^3.0.0" + exit "^0.1.2" + graceful-fs "^4.2.3" + jest-config "^25.3.0" + jest-docblock "^25.3.0" + jest-haste-map "^25.3.0" + jest-jasmine2 "^25.3.0" + jest-leak-detector "^25.3.0" + jest-message-util "^25.3.0" + jest-resolve "^25.3.0" + jest-runtime "^25.3.0" + jest-util "^25.3.0" + jest-worker "^25.2.6" + source-map-support "^0.5.6" + throat "^5.0.0" + jest-runtime@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-25.2.6.tgz#417e8d548c92bd10e659393a3bd5aa8cbdd71e6d" @@ -12403,6 +12796,37 @@ jest-runtime@^25.2.6: strip-bom "^4.0.0" yargs "^15.3.1" +jest-runtime@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-25.3.0.tgz#af4d40dbcc590fa5de9910cb6a120a13d131050b" + integrity sha512-gn5KYB1wxXRM3nfw8fVpthFu60vxQUCr+ShGq41+ZBFF3DRHZRKj3HDWVAVB4iTNBj2y04QeAo5cZ/boYaPg0w== + dependencies: + "@jest/console" "^25.3.0" + "@jest/environment" "^25.3.0" + "@jest/source-map" "^25.2.6" + "@jest/test-result" "^25.3.0" + "@jest/transform" "^25.3.0" + "@jest/types" "^25.3.0" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.3" + jest-config "^25.3.0" + jest-haste-map "^25.3.0" + jest-message-util "^25.3.0" + jest-mock "^25.3.0" + jest-regex-util "^25.2.6" + jest-resolve "^25.3.0" + jest-snapshot "^25.3.0" + jest-util "^25.3.0" + jest-validate "^25.3.0" + realpath-native "^2.0.0" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^15.3.1" + jest-serializer@^24.4.0, jest-serializer@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" @@ -12438,6 +12862,26 @@ jest-snapshot@^25.2.6: pretty-format "^25.2.6" semver "^6.3.0" +jest-snapshot@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-25.3.0.tgz#d4feb457494f4aaedcc83fbbf1ca21808fc3df71" + integrity sha512-GGpR6Oro2htJPKh5RX4PR1xwo5jCEjtvSPLW1IS7N85y+2bWKbiknHpJJRKSdGXghElb5hWaeQASJI4IiRayGg== + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^25.3.0" + "@types/prettier" "^1.19.0" + chalk "^3.0.0" + expect "^25.3.0" + jest-diff "^25.3.0" + jest-get-type "^25.2.6" + jest-matcher-utils "^25.3.0" + jest-message-util "^25.3.0" + jest-resolve "^25.3.0" + make-dir "^3.0.0" + natural-compare "^1.4.0" + pretty-format "^25.3.0" + semver "^6.3.0" + jest-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" @@ -12490,6 +12934,18 @@ jest-validate@^25.2.6: leven "^3.1.0" pretty-format "^25.2.6" +jest-validate@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-25.3.0.tgz#eb95fdee0039647bcd5d4be641b21e4a142a880c" + integrity sha512-3WuXgIZ4HXUvW6gk9twFFkT9j6zUorKnF2oEY8VEsHb7x5LGvVlN3WUsbqazVKuyXwvikO2zFJ/YTySMsMje2w== + dependencies: + "@jest/types" "^25.3.0" + camelcase "^5.3.1" + chalk "^3.0.0" + jest-get-type "^25.2.6" + leven "^3.1.0" + pretty-format "^25.3.0" + jest-watcher@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-25.2.6.tgz#19fc571d27f89a238ef497b9e037d8d41cf4a204" @@ -12502,6 +12958,18 @@ jest-watcher@^25.2.6: jest-util "^25.2.6" string-length "^3.1.0" +jest-watcher@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-25.3.0.tgz#fd03fd5ca52f02bd3161ab177466bf1bfdd34e5c" + integrity sha512-dtFkfidFCS9Ucv8azOg2hkiY3sgJEHeTLtGFHS+jfBEE7eRtrO6+2r1BokyDkaG2FOD7485r/SgpC1MFAENfeA== + dependencies: + "@jest/test-result" "^25.3.0" + "@jest/types" "^25.3.0" + ansi-escapes "^4.2.1" + chalk "^3.0.0" + jest-util "^25.3.0" + string-length "^3.1.0" + jest-worker@^24.6.0, jest-worker@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" @@ -12527,6 +12995,15 @@ jest@^25.2.6: import-local "^3.0.2" jest-cli "^25.2.6" +jest@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-25.3.0.tgz#7a5e59741d94b8662664c77a9f346246d6bf228b" + integrity sha512-iKd5ShQSHzFT5IL/6h5RZJhApgqXSoPxhp5HEi94v6OAw9QkF8T7X+liEU2eEHJ1eMFYTHmeWLrpBWulsDpaUg== + dependencies: + "@jest/core" "^25.3.0" + import-local "^3.0.2" + jest-cli "^25.3.0" + jetifier@^1.6.2: version "1.6.5" resolved "https://registry.yarnpkg.com/jetifier/-/jetifier-1.6.5.tgz#ea87324a4230bef20a9651178ecab978ee54a8cb" @@ -13900,6 +14377,14 @@ metro-babel-register@^0.56.0, metro-babel-register@^0.56.4: core-js "^2.2.2" escape-string-regexp "^1.0.5" +metro-babel-transformer@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.58.0.tgz#317c83b863cceb0573943815f1711fbcbe69b106" + integrity sha512-yBX3BkRhw2TCNPhe+pmLSgsAEA3huMvnX08UwjFqSXXI1aiqzRQobn92uKd1U5MM1Vx8EtXVomlJb95ZHNAv6A== + dependencies: + "@babel/core" "^7.0.0" + metro-source-map "0.58.0" + metro-babel-transformer@0.59.0: version "0.59.0" resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.59.0.tgz#dda99c75d831b00142c42c020c51c103b29f199d" @@ -14014,6 +14499,47 @@ metro-minify-uglify@^0.56.4: dependencies: uglify-es "^3.1.9" +metro-react-native-babel-preset@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.58.0.tgz#18f48d33fe124280ffabc000ab8b42c488d762a2" + integrity sha512-MRriNW+fF6jxABsgPphocUY6mIhmCm8idcrQZ58fT3Iti2vCdtkaK32TyCGUNUptzhUe2/cbE57j4aC+eaodAA== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-export-default-from" "^7.0.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-optional-chaining" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.0.0" + "@babel/plugin-syntax-export-default-from" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.2.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-exponentiation-operator" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-object-assign" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-regenerator" "^7.0.0" + "@babel/plugin-transform-runtime" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-sticky-regex" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.5.0" + "@babel/plugin-transform-unicode-regex" "^7.0.0" + "@babel/template" "^7.0.0" + react-refresh "^0.4.0" + metro-react-native-babel-preset@0.59.0: version "0.59.0" resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.59.0.tgz#20e020bc6ac9849e1477de1333d303ed42aba225" @@ -14110,6 +14636,17 @@ metro-react-native-babel-transformer@^0.56.0: metro-react-native-babel-preset "^0.56.4" metro-source-map "^0.56.4" +metro-react-native-babel-transformer@^0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.58.0.tgz#5da0e5a1b83c01d11626905fa59f34fda53a21a5" + integrity sha512-3A73+cRq1eUPQ8g+hPNGgMUMCGmtQjwqHfoG1DwinAoJ/kr4WOXWWbGZo0xHJNBe/zdHGl0uHcDCp2knPglTdQ== + dependencies: + "@babel/core" "^7.0.0" + babel-preset-fbjs "^3.3.0" + metro-babel-transformer "0.58.0" + metro-react-native-babel-preset "0.58.0" + metro-source-map "0.58.0" + metro-resolver@0.59.0: version "0.59.0" resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.59.0.tgz#fbc9d7c95f094c52807877d0011feffb9e896fad" @@ -14124,6 +14661,19 @@ metro-resolver@^0.56.4: dependencies: absolute-path "^0.0.0" +metro-source-map@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.58.0.tgz#e951b99f4c653239ce9323bb08339c6f1978a112" + integrity sha512-yvN1YPmejmgiiS7T1aKBiiUTHPw2Vcm3r2TZ+DY92z/9PR4alysIywrCs/fTHs8rbDcKM5VfPCKGLpkBrbKeOw== + dependencies: + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + invariant "^2.2.4" + metro-symbolicate "0.58.0" + ob1 "0.58.0" + source-map "^0.5.6" + vlq "^1.0.0" + metro-source-map@0.59.0: version "0.59.0" resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.59.0.tgz#e9beb9fc51bfb4e060f95820cf1508fc122d23f7" @@ -14150,6 +14700,17 @@ metro-source-map@^0.56.0, metro-source-map@^0.56.4: source-map "^0.5.6" vlq "^1.0.0" +metro-symbolicate@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.58.0.tgz#ba9fd52549c41fc1b656adaad7c8875726dd5abe" + integrity sha512-uIVxUQC1E26qOMj13dKROhwAa2FmZk5eR0NcBqej/aXmQhpr8LjJg2sondkoLKUp827Tf/Fm9+pS4icb5XiqCw== + dependencies: + invariant "^2.2.4" + metro-source-map "0.58.0" + source-map "^0.5.6" + through2 "^2.0.1" + vlq "^1.0.0" + metro-symbolicate@0.59.0: version "0.59.0" resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.59.0.tgz#fc7f93957a42b02c2bfc57ed1e8f393f5f636a54" @@ -15365,6 +15926,11 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +ob1@0.58.0: + version "0.58.0" + resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.58.0.tgz#484a1e9a63a8b79d9ea6f3a83b2a42110faac973" + integrity sha512-uZP44cbowAfHafP1k4skpWItk5iHCoRevMfrnUvYCfyNNPPJd3rfDCyj0exklWi2gDXvjlj2ObsfiqP/bs/J7Q== + ob1@0.59.0: version "0.59.0" resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.59.0.tgz#ee103619ef5cb697f2866e3577da6f0ecd565a36" @@ -17104,6 +17670,16 @@ pretty-format@^25.1.0, pretty-format@^25.2.6: ansi-styles "^4.0.0" react-is "^16.12.0" +pretty-format@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.3.0.tgz#d0a4f988ff4a6cd350342fdabbb809aeb4d49ad5" + integrity sha512-wToHwF8bkQknIcFkBqNfKu4+UZqnrLn/Vr+wwKQwwvPzkBfDDKp/qIabFqdgtoi5PEnM8LFByVsOrHoa3SpTVA== + dependencies: + "@jest/types" "^25.3.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + pretty-hrtime@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -18751,6 +19327,13 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +serialize-error@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-6.0.0.tgz#ccfb887a1dd1c48d6d52d7863b92544331fd752b" + integrity sha512-3vmBkMZLQO+BR4RPHcyRGdE09XCF6cvxzk2N2qn8Er3F91cy8Qt7VvEbZBOpaL53qsBbe2cFOefU6tRY6WDelA== + dependencies: + type-fest "^0.12.0" + serialize-error@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" @@ -20407,6 +20990,11 @@ type-detect@4.0.8: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-fest@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.12.0.tgz#f57a27ab81c68d136a51fd71467eff94157fa1ee" + integrity sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg== + type-fest@^0.3.0, type-fest@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"