diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a784b4611..fc76b5865 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,6 +25,7 @@ This repository is split into two packages: _Note: you must use the `--watchFolders` flag with the `start` command when testing the CLI with `yarn link` like this. Otherwise Metro can't find the symlinked folder and this may result in errors such as `ReferenceError: SHA-1 for file ... is not computed`._ ### Setup + Because of a modular design of the CLI, we recommend developing using symbolic links to its packages. This way you can use it seamlessly in the tested project, as you'd use the locally installed CLI. Here's what you need to run in the terminal: #### yarn v1 @@ -33,10 +34,12 @@ Because of a modular design of the CLI, we recommend developing using symbolic l cd /path/to/cloned/cli/ yarn link-packages ``` + And then: + ```sh cd /my/new/react-native/project/ -yarn link "@react-native-community/cli-platform-ios" "@react-native-community/cli-platform-android" "@react-native-community/cli" "@react-native-community/cli-server-api" "@react-native-community/cli-types" "@react-native-community/cli-tools" "@react-native-community/cli-debugger-ui" +yarn link "@react-native-community/cli-platform-ios" "@react-native-community/cli-platform-android" "@react-native-community/cli" "@react-native-community/cli-server-api" "@react-native-community/cli-types" "@react-native-community/cli-tools" "@react-native-community/cli-debugger-ui" "@react-native-community/cli-hermes" ``` Once you're done with testing and you'd like to get back to regular setup, run `yarn unlink` instead of `yarn link` from above command. Then `yarn install --force`. @@ -51,6 +54,7 @@ yarn link /path/to/cloned/cli/ --all When you'd like to revert to a regular setup, you will need to revert the changes made to the `resolutions` field of `package.json`. ### Running + ```sh yarn react-native start --watchFolders /path/to/cloned/cli/ yarn react-native run-android diff --git a/docs/commands.md b/docs/commands.md index 970c97be8..c05e42f02 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -17,6 +17,7 @@ React Native CLI comes with following commands: - [`uninstall`](#uninstall) - [`unlink`](#unlink) - [`upgrade`](#upgrade) +- [`profile-hermes`](#profile-hermes) ### `bundle` @@ -546,3 +547,48 @@ Upgrade your app's template files to the specified or latest npm version using [ Using this command is a recommended way of upgrading relatively simple React Native apps with not too many native libraries linked. The more iOS and Android build files are modified, the higher chance for a conflicts. The command will guide you on how to continue upgrade process manually in case of failure. _Note: If you'd like to upgrade using this method from React Native version lower than 0.59.0, you may use a standalone version of this CLI: `npx @react-native-community/cli upgrade`._ + +### `profile-hermes` + +Usage: + +```sh +react-native profile-hermes [destinationDir] +``` + +Pull and convert a Hermes tracing profile to Chrome tracing profile, then store it in the directory of the local machine. + +- `destinationDir` is optional, if provided, pull the file to that directory + > default: pull to the current React Native app root directory + +#### Options + +#### `--filename [string]` + +File name of the profile to be downloaded, eg. sampling-profiler-trace8593107139682635366.cpuprofile. + +> default: pull the latest file + +#### `--raw` + +Pulls the original Hermes tracing profile without any transformation + +#### `--sourcemap-path [string]` + +The local path to your source map file if you generated it manually, ex. `/tmp/sourcemap.json` + +#### `--generate-sourcemap` + +Generate the JS bundle and source map in `os.tmpdir()` + +#### '--port [number]', + +The running metro server port number + +> default: 8081 + +### Notes on source map + +This step is recommended in order for the source map to be generated: + +If you are planning on building a debug APK, that will run without the packager, by invoking `./gradlew assembleDebug` you can simply set `bundleInDebug: true` in your app/build.gradle file, inside the `project.ext.react` map. diff --git a/packages/cli-hermes/package.json b/packages/cli-hermes/package.json new file mode 100644 index 000000000..9e76ae880 --- /dev/null +++ b/packages/cli-hermes/package.json @@ -0,0 +1,26 @@ +{ + "name": "@react-native-community/cli-hermes", + "version": "4.11.0", + "license": "MIT", + "main": "build/index.js", + "publishConfig": { + "access": "public" + }, + "types": "build/index.d.ts", + "dependencies": { + "@react-native-community/cli-tools": "^4.11.0", + "@react-native-community/cli-platform-android": "^4.11.0", + "chalk": "^3.0.0", + "hermes-profile-transformer": "^0.0.6", + "ip": "^1.1.5" + }, + "files": [ + "build", + "!*.d.ts", + "!*.map" + ], + "devDependencies": { + "@react-native-community/cli-types": "^4.10.1", + "@types/ip": "^1.1.0" + } +} diff --git a/packages/cli-hermes/src/index.ts b/packages/cli-hermes/src/index.ts new file mode 100644 index 000000000..6d7cef0e7 --- /dev/null +++ b/packages/cli-hermes/src/index.ts @@ -0,0 +1,2 @@ +import profileHermes from './profileHermes/index'; +export default profileHermes; diff --git a/packages/cli-hermes/src/profileHermes/downloadProfile.ts b/packages/cli-hermes/src/profileHermes/downloadProfile.ts new file mode 100644 index 000000000..201d8dd38 --- /dev/null +++ b/packages/cli-hermes/src/profileHermes/downloadProfile.ts @@ -0,0 +1,128 @@ +import {Config} from '@react-native-community/cli-types'; +import {execSync} from 'child_process'; +import {logger, CLIError} from '@react-native-community/cli-tools'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import transformer from 'hermes-profile-transformer'; +import {findSourcemap, generateSourcemap} from './sourcemapUtils'; +import { + getAndroidProject, + getPackageName, +} from '@react-native-community/cli-platform-android'; +/** + * Get the last modified hermes profile + * @param packageName + */ +function getLatestFile(packageName: string): string { + try { + const file = execSync(`adb shell run-as ${packageName} ls cache/ -tp | grep -v /$ | egrep '\.cpuprofile' | head -1 + `); + return file.toString().trim(); + } catch (e) { + throw new Error(e); + } +} + +function execSyncWithLog(command: string) { + logger.debug(`${command}`); + return execSync(command); +} + +/** + * Pull and convert a Hermes tracing profile to Chrome tracing profile + * @param ctx + * @param dstPath + * @param fileName + * @param sourceMapPath + * @param raw + * @param generateSourceMap + */ +export async function downloadProfile( + ctx: Config, + dstPath: string, + filename?: string, + sourcemapPath?: string, + raw?: boolean, + shouldGenerateSourcemap?: boolean, + port?: string, +) { + try { + const androidProject = getAndroidProject(ctx); + const packageName = getPackageName(androidProject); + + // If file name is not specified, pull the latest file from device + const file = filename || (await getLatestFile(packageName)); + if (!file) { + throw new CLIError( + 'There is no file in the cache/ directory. Did you record a profile from the developer menu?', + ); + } + + logger.info(`File to be pulled: ${file}`); + + // If destination path is not specified, pull to the current directory + dstPath = dstPath || ctx.root; + + logger.debug('Internal commands run to pull the file:'); + + // Copy the file from device's data to sdcard, then pull the file to a temp directory + execSyncWithLog(`adb shell run-as ${packageName} cp cache/${file} /sdcard`); + + // If --raw, pull the hermes profile to dstPath + if (raw) { + execSyncWithLog(`adb pull /sdcard/${file} ${dstPath}`); + logger.success(`Successfully pulled the file to ${dstPath}/${file}`); + } + + // Else: transform the profile to Chrome format and pull it to dstPath + else { + const osTmpDir = os.tmpdir(); + const tempFilePath = path.join(osTmpDir, file); + + execSyncWithLog(`adb pull /sdcard/${file} ${tempFilePath}`); + + // If path to source map is not given + if (!sourcemapPath) { + // Get or generate the source map + if (shouldGenerateSourcemap) { + sourcemapPath = await generateSourcemap(port); + } else { + sourcemapPath = await findSourcemap(ctx, port); + } + + // Run without source map + if (!sourcemapPath) { + logger.warn( + 'Cannot find source maps, running the transformer without it', + ); + logger.info( + 'Instructions on how to get source maps: set `bundleInDebug: true` in your app/build.gradle file, inside the `project.ext.react` map.', + ); + } + } + + // Run transformer tool to convert from Hermes to Chrome format + const events = await transformer( + tempFilePath, + sourcemapPath, + 'index.bundle', + ); + + const transformedFilePath = `${dstPath}/${path.basename( + file, + '.cpuprofile', + )}-converted.json`; + fs.writeFileSync( + transformedFilePath, + JSON.stringify(events, undefined, 4), + 'utf-8', + ); + logger.success( + `Successfully converted to Chrome tracing format and pulled the file to ${transformedFilePath}`, + ); + } + } catch (e) { + throw e; + } +} diff --git a/packages/cli-hermes/src/profileHermes/index.ts b/packages/cli-hermes/src/profileHermes/index.ts new file mode 100644 index 000000000..6ab7da33b --- /dev/null +++ b/packages/cli-hermes/src/profileHermes/index.ts @@ -0,0 +1,77 @@ +import {logger, CLIError} from '@react-native-community/cli-tools'; +import {Config} from '@react-native-community/cli-types'; +import {downloadProfile} from './downloadProfile'; + +type Options = { + filename?: string; + raw?: boolean; + sourcemapPath?: string; + generateSourcemap?: boolean; + port?: string; +}; + +async function profileHermes( + [dstPath]: Array, + ctx: Config, + options: Options, +) { + try { + logger.info( + 'Downloading a Hermes Sampling Profiler from your Android device...', + ); + if (!options.filename) { + logger.info('No filename is provided, pulling latest file'); + } + await downloadProfile( + ctx, + dstPath, + options.filename, + options.sourcemapPath, + options.raw, + options.generateSourcemap, + options.port, + ); + } catch (err) { + throw err as CLIError; + } +} + +export default { + name: 'profile-hermes [destinationDir]', + description: + 'Pull and convert a Hermes tracing profile to Chrome tracing profile, then store it in the directory of the local machine', + func: profileHermes, + options: [ + { + name: '--filename [string]', + description: + 'File name of the profile to be downloaded, eg. sampling-profiler-trace8593107139682635366.cpuprofile', + }, + { + name: '--raw', + description: + 'Pulls the original Hermes tracing profile without any transformation', + }, + { + name: '--sourcemap-path [string]', + description: + 'The local path to your source map file, eg. /tmp/sourcemap.json', + }, + { + name: '--generate-sourcemap', + description: 'Generates the JS bundle and source map', + }, + { + name: '--port [number]', + default: process.env.RCT_METRO_PORT || 8081, + parse: (val: number) => String(val), + }, + ], + examples: [ + { + desc: + 'Download the Hermes Sampling Profiler to the directory on the local machine', + cmd: 'profile-hermes /tmp', + }, + ], +}; diff --git a/packages/cli-hermes/src/profileHermes/sourcemapUtils.ts b/packages/cli-hermes/src/profileHermes/sourcemapUtils.ts new file mode 100644 index 000000000..b1f3ee3df --- /dev/null +++ b/packages/cli-hermes/src/profileHermes/sourcemapUtils.ts @@ -0,0 +1,114 @@ +import {Config} from '@react-native-community/cli-types'; +import {logger, CLIError} from '@react-native-community/cli-tools'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import {SourceMap} from 'hermes-profile-transformer'; +import ip from 'ip'; +import {fetch} from '@react-native-community/cli-tools'; + +function getTempFilePath(filename: string) { + return path.join(os.tmpdir(), filename); +} + +function writeJsonSync(targetPath: string, data: any) { + let json; + try { + json = JSON.stringify(data); + } catch (e) { + throw new CLIError( + `Failed to serialize data to json before writing to ${targetPath}`, + e, + ); + } + + try { + fs.writeFileSync(targetPath, json, 'utf-8'); + } catch (e) { + throw new CLIError(`Failed to write json to ${targetPath}`, e); + } +} + +async function getSourcemapFromServer( + port?: string, +): Promise { + logger.debug('Getting source maps from Metro packager server'); + const DEBUG_SERVER_PORT = port || '8081'; + const IP_ADDRESS = ip.address(); + const PLATFORM = 'android'; + + const requestURL = `http://${IP_ADDRESS}:${DEBUG_SERVER_PORT}/index.map?platform=${PLATFORM}&dev=true`; + try { + const {data} = await fetch(requestURL); + return data as SourceMap; + } catch (e) { + logger.debug(`Failed to fetch source map from "${requestURL}"`); + return undefined; + } +} + +/** + * Generate a sourcemap by fetching it from a running metro server + */ +export async function generateSourcemap( + port?: string, +): Promise { + // Fetch the source map to a temp directory + const sourceMapPath = getTempFilePath('index.map'); + const sourceMapResult = await getSourcemapFromServer(port); + + if (sourceMapResult) { + logger.debug('Using source maps from Metro packager server'); + writeJsonSync(sourceMapPath, sourceMapResult); + logger.debug( + `Successfully obtained the source map and stored it in ${sourceMapPath}`, + ); + return sourceMapPath; + } else { + logger.error('Cannot obtain source maps from Metro packager server'); + return undefined; + } +} + +/** + * + * @param ctx + */ +export async function findSourcemap( + ctx: Config, + port?: string, +): Promise { + const intermediateBuildPath = path.join( + ctx.root, + 'android', + 'app', + 'build', + 'intermediates', + 'sourcemaps', + 'react', + 'debug', + 'index.android.bundle.packager.map', + ); + + const generatedBuildPath = path.join( + ctx.root, + 'android', + 'app', + 'build', + 'generated', + 'sourcemaps', + 'react', + 'debug', + 'index.android.bundle.map', + ); + + if (fs.existsSync(generatedBuildPath)) { + logger.debug(`Getting the source map from ${generateSourcemap}`); + return generatedBuildPath; + } else if (fs.existsSync(intermediateBuildPath)) { + logger.debug(`Getting the source map from ${intermediateBuildPath}`); + return intermediateBuildPath; + } else { + return generateSourcemap(port); + } +} diff --git a/packages/cli-hermes/tsconfig.json b/packages/cli-hermes/tsconfig.json new file mode 100644 index 000000000..1544a66ab --- /dev/null +++ b/packages/cli-hermes/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + }, + "references": [ + {"path": "../tools"}, + {"path": "../cli-types"}, + {"path": "../platform-android"} + ] +} diff --git a/packages/cli/package.json b/packages/cli/package.json index e7cf33ef6..1d49f8238 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -30,6 +30,7 @@ "dependencies": { "@hapi/joi": "^15.0.3", "@react-native-community/cli-debugger-ui": "^4.9.0", + "@react-native-community/cli-hermes": "^4.11.0", "@react-native-community/cli-server-api": "^4.11.0", "@react-native-community/cli-tools": "^4.11.0", "@react-native-community/cli-types": "^4.10.1", diff --git a/packages/cli/src/commands/bundle/buildBundle.ts b/packages/cli/src/commands/bundle/buildBundle.ts index 72abc912e..fa0a6007c 100644 --- a/packages/cli/src/commands/bundle/buildBundle.ts +++ b/packages/cli/src/commands/bundle/buildBundle.ts @@ -84,7 +84,6 @@ async function buildBundle( minify: args.minify !== undefined ? args.minify : !args.dev, platform: args.platform, }; - const server = new Server(config); try { diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 94fdebfbf..fc5b657fe 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -11,6 +11,7 @@ import info from './info/info'; import config from './config/config'; import init from './init'; import doctor from './doctor'; +import profileHermes from '@react-native-community/cli-hermes'; export const projectCommands = [ start, @@ -24,6 +25,7 @@ export const projectCommands = [ info, config, doctor, + profileHermes, ] as Command[]; export const detachedCommands = [init, doctor] as DetachedCommand[]; diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index daf679bae..f3d42e37b 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -8,6 +8,7 @@ {"path": "../tools"}, {"path": "../cli-types"}, {"path": "../debugger-ui"}, - {"path": "../cli-server-api"} + {"path": "../cli-server-api"}, + {"path": "../cli-hermes"} ] } diff --git a/packages/platform-android/src/commands/runAndroid/index.ts b/packages/platform-android/src/commands/runAndroid/index.ts index b0ed8b54d..65b818067 100644 --- a/packages/platform-android/src/commands/runAndroid/index.ts +++ b/packages/platform-android/src/commands/runAndroid/index.ts @@ -22,11 +22,7 @@ import { CLIError, } from '@react-native-community/cli-tools'; import warnAboutManuallyLinkedLibs from '../../link/warnAboutManuallyLinkedLibs'; - -// Validates that the package name is correct -function validatePackageName(packageName: string) { - return /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.test(packageName); -} +import {getAndroidProject, getPackageName} from '../../utils/getAndroidProject'; function displayWarnings(config: Config, args: Flags) { warnAboutManuallyLinkedLibs(config); @@ -64,15 +60,7 @@ type AndroidProject = NonNullable; */ async function runAndroid(_argv: Array, config: Config, args: Flags) { displayWarnings(config, args); - const androidProject = config.project.android; - - if (!androidProject) { - throw new CLIError(` - Android project not found. Are you sure this is a React Native project? - If your Android files are located in a non-standard location (e.g. not inside \'android\' folder), consider setting - \`project.android.sourceDir\` option to point to a new location. -`); - } + const androidProject = getAndroidProject(config); if (args.jetifier) { logger.info( @@ -125,31 +113,8 @@ function buildAndRun(args: Flags, androidProject: AndroidProject) { process.chdir(androidProject.sourceDir); const cmd = process.platform.startsWith('win') ? 'gradlew.bat' : './gradlew'; - // "app" is usually the default value for Android apps with only 1 app - const {appName, manifestPath} = androidProject; const {appFolder} = args; - const androidManifest = fs.readFileSync(manifestPath, 'utf8'); - - let packageNameMatchArray = androidManifest.match(/package="(.+?)"/); - if (!packageNameMatchArray || packageNameMatchArray.length === 0) { - throw new CLIError( - `Failed to build the app: No package name found. Found errors in ${chalk.underline.dim( - `${appFolder || appName}/src/main/AndroidManifest.xml`, - )}`, - ); - } - - let packageName = packageNameMatchArray[1]; - - if (!validatePackageName(packageName)) { - logger.warn( - `Invalid application's package name "${chalk.bgRed( - packageName, - )}" in 'AndroidManifest.xml'. Read guidelines for setting the package name here: ${chalk.underline.dim( - 'https://developer.android.com/studio/build/application-id', - )}`, - ); // we can also directly add the package naming rules here - } + const packageName = getPackageName(androidProject, appFolder); const adbPath = getAdbPath(); if (args.deviceId) { diff --git a/packages/platform-android/src/index.ts b/packages/platform-android/src/index.ts index 828fcb43b..d03bb9749 100644 --- a/packages/platform-android/src/index.ts +++ b/packages/platform-android/src/index.ts @@ -5,3 +5,4 @@ export {default as linkConfig} from './link'; export {default as commands} from './commands'; export {projectConfig, dependencyConfig} from './config'; +export {getAndroidProject, getPackageName} from './utils/getAndroidProject'; diff --git a/packages/platform-android/src/utils/getAndroidProject.ts b/packages/platform-android/src/utils/getAndroidProject.ts new file mode 100644 index 000000000..64d9c7031 --- /dev/null +++ b/packages/platform-android/src/utils/getAndroidProject.ts @@ -0,0 +1,56 @@ +import {Config, AndroidProjectConfig} from '@react-native-community/cli-types'; +import {logger, CLIError} from '@react-native-community/cli-tools'; +import fs from 'fs'; +import chalk from 'chalk'; + +export function getAndroidProject(config: Config) { + const androidProject = config.project.android; + + if (!androidProject) { + throw new CLIError(` + Android project not found. Are you sure this is a React Native project? + If your Android files are located in a non-standard location (e.g. not inside \'android\' folder), consider setting + \`project.android.sourceDir\` option to point to a new location. + `); + } + return androidProject; +} + +/** + * Get the package name of the running React Native app + * @param config + */ +export function getPackageName( + androidProject: AndroidProjectConfig, + appFolder?: string, +) { + const {appName, manifestPath} = androidProject; + const androidManifest = fs.readFileSync(manifestPath, 'utf8'); + + let packageNameMatchArray = androidManifest.match(/package="(.+?)"/); + if (!packageNameMatchArray || packageNameMatchArray.length === 0) { + throw new CLIError( + `Failed to build the app: No package name found. Found errors in ${chalk.underline.dim( + `${appFolder || appName}/src/main/AndroidManifest.xml`, + )}`, + ); + } + + let packageName = packageNameMatchArray[1]; + + if (!validatePackageName(packageName)) { + logger.warn( + `Invalid application's package name "${chalk.bgRed( + packageName, + )}" in 'AndroidManifest.xml'. Read guidelines for setting the package name here: ${chalk.underline.dim( + 'https://developer.android.com/studio/build/application-id', + )}`, + ); + } + return packageName; +} + +// Validates that the package name is correct +function validatePackageName(packageName: string) { + return /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.test(packageName); +} diff --git a/yarn.lock b/yarn.lock index 6e9767698..d73b34964 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2276,6 +2276,13 @@ dependencies: "@types/hapi__joi" "*" +"@types/ip@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@types/ip/-/ip-1.1.0.tgz#aec4f5bfd49e4a4c53b590d88c36eb078827a7c0" + integrity sha512-dwNe8gOoF70VdL6WJBwVHtQmAX4RMd62M+mAB9HQFjG1/qiCLM/meRy95Pd14FYBbEDwCq7jgJs89cHpLBu4HQ== + dependencies: + "@types/node" "*" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" @@ -2737,7 +2744,7 @@ array-ify@^1.0.0: resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= -array-includes@^3.0.3: +array-includes@^3.0.3, array-includes@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== @@ -3448,6 +3455,14 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" @@ -4767,9 +4782,9 @@ eslint-module-utils@^2.4.1: pkg-dir "^2.0.0" eslint-plugin-eslint-comments@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.1.2.tgz#4ef6c488dbe06aa1627fea107b3e5d059fc8a395" - integrity sha512-QexaqrNeteFfRTad96W+Vi4Zj1KFbkHHNMMaHZEYcovKav6gdomyGzaxSDSL3GoIyUOo078wRAdYlu1caiauIQ== + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa" + integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ== dependencies: escape-string-regexp "^1.0.5" ignore "^5.0.5" @@ -5742,6 +5757,13 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hermes-profile-transformer@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz#bd0f5ecceda80dd0ddaae443469ab26fb38fc27b" + integrity sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ== + dependencies: + source-map "^0.7.3" + hex-color-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" @@ -6078,7 +6100,7 @@ ip-regex@^2.1.0: resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= -ip@1.1.5: +ip@1.1.5, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= @@ -7166,11 +7188,11 @@ jsprim@^1.2.2: verror "1.10.0" jsx-ast-utils@^2.0.1: - version "2.2.3" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz#8a9364e402448a3ce7f14d357738310d9248054f" - integrity sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA== + version "2.4.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e" + integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w== dependencies: - array-includes "^3.0.3" + array-includes "^3.1.1" object.assign "^4.1.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: @@ -10026,13 +10048,20 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.5, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.15.1, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1, resolve@^1.9.0: +resolve@^1.1.5, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.15.1, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1: version "1.15.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== dependencies: path-parse "^1.0.6" +resolve@^1.9.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"