From bef21d4365cab2c4139c1229d6757cfc6594ef4c Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Mon, 14 Aug 2023 07:34:01 -0700 Subject: [PATCH] Add auto-generation of TypeScript definitions on build (#38990) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/38990 This PR adds auto-generation of Typescript definitions from Flow source code for packages using the shared monorepo build setup (https://github.com/facebook/react-native/pull/38718). Today, these are the following Node.js packages: - `packages/community-cli-plugin` - `packages/dev-middleware` (⬅️ `emitTypeScriptDefs` enabled) This also improves emitted Flow definitions (`.js.flow`), by using [`flow-api-translator`](https://www.npmjs.com/package/flow-api-translator) to strip implementations. **All changes** - Include `flow-api-translator` and configure this to emit type definitions as part of `yarn build`. - Add translation from Flow source to TypeScript definitions (`.d.ts`) adjacent to each built file. - Improve emitted Flow definitions (`.js.flow`), by using `flow-api-translator` to strip implementations (previously, source files were copied). The Flow and TS defs now mirror each other. - Add `emitFlowDefs` and `emitTypeScriptDefs` options to build config to configure the above. - Integrate TypeScript compiler to perform program validation on emitted `.d.ts` files. - This is based on this guide: https://github.com/microsoft/TypeScript-wiki/blob/main/Using-the-Compiler-API.md#a-minimal-compiler. - Throw an exception on the `rewritePackageExports` step if a package does not define an `"exports"` field. - Add minimal `flow-typed` definitions for `typescript` 😄. **Notes on [`flow-api-translator`](https://www.npmjs.com/package/flow-api-translator)** This project is experimental but is in a more mature state than when we evaluated it earlier in 2023. - It's now possible to run this tool on our new Node.js packages, since they are exclusively authored using `import`/`export` syntax (a requirement of the tool). - As a safety net, we run the TypeScript compiler against the generated program, which will fail the build. Changelog: [Internal] Differential Revision: D48312463 fbshipit-source-id: d53dc3f4fe6758a49cdb4759929a36de641d2a8d --- flow-typed/npm/@tsconfig/node18_v1.x.x.js | 13 ++ flow-typed/npm/typescript_v5.x.x.js | 56 ++++++++ package.json | 2 + packages/dev-middleware/src/index.js | 2 +- scripts/build/babel/node.config.js | 44 ++++++ scripts/build/build.js | 156 +++++++++++++++++----- scripts/build/config.js | 85 ++++++++---- yarn.lock | 66 ++++++++- 8 files changed, 360 insertions(+), 64 deletions(-) create mode 100644 flow-typed/npm/@tsconfig/node18_v1.x.x.js create mode 100644 flow-typed/npm/typescript_v5.x.x.js create mode 100644 scripts/build/babel/node.config.js diff --git a/flow-typed/npm/@tsconfig/node18_v1.x.x.js b/flow-typed/npm/@tsconfig/node18_v1.x.x.js new file mode 100644 index 00000000000000..3e7f193200ffcb --- /dev/null +++ b/flow-typed/npm/@tsconfig/node18_v1.x.x.js @@ -0,0 +1,13 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +declare module '@tsconfig/node18/tsconfig.json' { + declare module.exports: any; +} diff --git a/flow-typed/npm/typescript_v5.x.x.js b/flow-typed/npm/typescript_v5.x.x.js new file mode 100644 index 00000000000000..cf194876daf0c2 --- /dev/null +++ b/flow-typed/npm/typescript_v5.x.x.js @@ -0,0 +1,56 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +declare module 'typescript' { + declare enum ModuleResolutionKind { + Classic = 1, + NodeJs = 2, + Node10 = 2, + Node16 = 3, + NodeNext = 99, + Bundler = 100, + } + + declare type SourceFile = $ReadOnly<{ + fileName: string, + text: string, + ... + }>; + + declare type Diagnostic = $ReadOnly<{ + file?: SourceFile, + start?: number, + messageText: string, + ... + }>; + + declare type EmitResult = $ReadOnly<{ + diagnostics: Array, + ... + }>; + + declare type Program = $ReadOnly<{ + emit: () => EmitResult, + ... + }>; + + declare type TypeScriptAPI = { + createProgram(files: Array, compilerOptions: Object): Program, + flattenDiagnosticMessageText: (...messageText: Array) => string, + getLineAndCharacterOfPosition( + file: SourceFile, + start?: number, + ): $ReadOnly<{line: number, character: number}>, + ModuleResolutionKind: typeof ModuleResolutionKind, + ... + }; + + declare module.exports: TypeScriptAPI; +} diff --git a/package.json b/package.json index 983b9f055026f7..6b1dcaafa2e27a 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "@pkgjs/parseargs": "^0.11.0", "@react-native/metro-babel-transformer": "^0.73.11", "@react-native/metro-config": "^0.73.0", + "@tsconfig/node18": "1.0.1", "@types/react": "^18.0.18", "@typescript-eslint/parser": "^5.57.1", "async": "^3.2.2", @@ -81,6 +82,7 @@ "eslint-plugin-react-native": "^4.0.0", "eslint-plugin-redundant-undefined": "^0.4.0", "eslint-plugin-relay": "^1.8.3", + "flow-api-translator": "^0.15.1", "flow-bin": "^0.214.0", "glob": "^7.1.1", "hermes-eslint": "0.15.0", diff --git a/packages/dev-middleware/src/index.js b/packages/dev-middleware/src/index.js index c95fbd8400e1d4..b1cd97b5d4555d 100644 --- a/packages/dev-middleware/src/index.js +++ b/packages/dev-middleware/src/index.js @@ -17,4 +17,4 @@ if (!process.env.BUILD_EXCLUDE_BABEL_REGISTER) { require('../../../scripts/build/babel-register').registerForMonorepo(); } -module.exports = require('./index.flow'); +export * from './index.flow'; diff --git a/scripts/build/babel/node.config.js b/scripts/build/babel/node.config.js new file mode 100644 index 00000000000000..95972f63b0695d --- /dev/null +++ b/scripts/build/babel/node.config.js @@ -0,0 +1,44 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + * @oncall react_native + */ + +/*:: +import type {BabelCoreOptions} from '@babel/core'; +*/ + +const TARGET_NODE_VERSION = '18'; + +const config /*: BabelCoreOptions */ = { + presets: [ + '@babel/preset-flow', + [ + '@babel/preset-env', + { + targets: { + node: TARGET_NODE_VERSION, + }, + }, + ], + ], + plugins: [ + [ + 'transform-define', + { + 'process.env.BUILD_EXCLUDE_BABEL_REGISTER': true, + }, + ], + [ + 'minify-dead-code-elimination', + {keepFnName: true, keepFnArgs: true, keepClassName: true}, + ], + ], +}; + +module.exports = config; diff --git a/scripts/build/build.js b/scripts/build/build.js index c7c65d83ea7cd0..13c1224d536d3b 100644 --- a/scripts/build/build.js +++ b/scripts/build/build.js @@ -12,14 +12,22 @@ const babel = require('@babel/core'); const {parseArgs} = require('@pkgjs/parseargs'); const chalk = require('chalk'); +const translate = require('flow-api-translator'); const glob = require('glob'); const micromatch = require('micromatch'); -const fs = require('fs'); +const {promises: fs} = require('fs'); const path = require('path'); const prettier = require('prettier'); -const {buildConfig, getBabelConfig} = require('./config'); - -const PACKAGES_DIR /*: string */ = path.resolve(__dirname, '../../packages'); +const ts = require('typescript'); +const { + buildConfig, + getBabelConfig, + getBuildOptions, + getTypeScriptCompilerOptions, +} = require('./config'); + +const REPO_ROOT = path.resolve(__dirname, '../..'); +const PACKAGES_DIR /*: string */ = path.join(REPO_ROOT, 'packages'); const SRC_DIR = 'src'; const BUILD_DIR = 'dist'; const JS_FILES_PATTERN = '**/*.js'; @@ -32,7 +40,7 @@ const config = { }, }; -function build() { +async function build() { const { positionals: packageNames, values: {help}, @@ -53,35 +61,48 @@ function build() { console.log('\n' + chalk.bold.inverse('Building packages') + '\n'); - if (packageNames.length) { - packageNames - .filter(packageName => packageName in buildConfig.packages) - .forEach(buildPackage); - } else { - Object.keys(buildConfig.packages).forEach(buildPackage); + const packagesToBuild = packageNames.length + ? packageNames.filter(packageName => packageName in buildConfig.packages) + : Object.keys(buildConfig.packages); + + for (const packageName of packagesToBuild) { + await buildPackage(packageName); } process.exitCode = 0; } -function buildPackage(packageName /*: string */) { +async function buildPackage(packageName /*: string */) { + const {emitTypeScriptDefs} = getBuildOptions(packageName); const files = glob.sync( path.resolve(PACKAGES_DIR, packageName, SRC_DIR, '**/*'), {nodir: true}, ); - const packageJsonPath = path.join(PACKAGES_DIR, packageName, 'package.json'); process.stdout.write( `${packageName} ${chalk.dim('.').repeat(72 - packageName.length)} `, ); - files.forEach(file => buildFile(path.normalize(file), true)); - rewritePackageExports(packageJsonPath); + + // Build all files matched for package + for (const file of files) { + await buildFile(path.normalize(file), true); + } + + // Validate program for emitted .d.ts files + if (emitTypeScriptDefs) { + validateTypeScriptDefs(packageName); + } + + // Rewrite package.json "exports" field (src -> dist) + await rewritePackageExports(packageName); + process.stdout.write(chalk.reset.inverse.bold.green(' DONE ') + '\n'); } -function buildFile(file /*: string */, silent /*: boolean */ = false) { +async function buildFile(file /*: string */, silent /*: boolean */ = false) { const packageName = getPackageName(file); const buildPath = getBuildPath(file); + const {emitFlowDefs, emitTypeScriptDefs} = getBuildOptions(packageName); const logResult = ({copied, desc} /*: {copied: boolean, desc?: string} */) => silent || @@ -97,24 +118,43 @@ function buildFile(file /*: string */, silent /*: boolean */ = false) { return; } - fs.mkdirSync(path.dirname(buildPath), {recursive: true}); + await fs.mkdir(path.dirname(buildPath), {recursive: true}); if (!micromatch.isMatch(file, JS_FILES_PATTERN)) { - fs.copyFileSync(file, buildPath); + await fs.copyFile(file, buildPath); logResult({copied: true, desc: 'copy'}); - } else { - const transformed = prettier.format( - babel.transformFileSync(file, getBabelConfig(packageName)).code, - {parser: 'babel'}, - ); - fs.writeFileSync(buildPath, transformed); + return; + } - if (/@flow/.test(fs.readFileSync(file, 'utf-8'))) { - fs.copyFileSync(file, buildPath + '.flow'); - } + const source = await fs.readFile(file, 'utf-8'); + const prettierConfig = {parser: 'babel'}; - logResult({copied: true}); + // Transform source file using Babel + const transformed = prettier.format( + (await babel.transformFileAsync(file, getBabelConfig(packageName))).code, + prettierConfig, + ); + await fs.writeFile(buildPath, transformed); + + // Translate source Flow types for each type definition target + if (/@flow/.test(source)) { + await Promise.all([ + emitFlowDefs + ? fs.writeFile( + buildPath + '.flow', + await translate.translateFlowToFlowDef(source, prettierConfig), + ) + : null, + emitTypeScriptDefs + ? fs.writeFile( + buildPath.replace(/\.js$/, '') + '.d.ts', + await translate.translateFlowToTSDef(source, prettierConfig), + ) + : null, + ]); } + + logResult({copied: true}); } function getPackageName(file /*: string */) /*: string */ { @@ -130,16 +170,22 @@ function getBuildPath(file /*: string */) /*: string */ { ); } -function rewritePackageExports(packageJsonPath /*: string */) { - const pkg = JSON.parse(fs.readFileSync(packageJsonPath, {encoding: 'utf8'})); +async function rewritePackageExports(packageName /*: string */) { + const packageJsonPath = path.join(PACKAGES_DIR, packageName, 'package.json'); + const pkg = JSON.parse(await fs.readFile(packageJsonPath, 'utf8')); if (pkg.exports == null) { - return; + throw new Error( + packageName + + ' does not define an "exports" field in its package.json. As part ' + + 'of the build setup, this field must be used in order to rewrite ' + + 'paths to built files in production.', + ); } pkg.exports = rewriteExportsField(pkg.exports); - fs.writeFileSync( + await fs.writeFile( packageJsonPath, prettier.format(JSON.stringify(pkg), {parser: 'json'}), ); @@ -173,6 +219,49 @@ function rewriteExportsTarget(target /*: string */) /*: string */ { return target.replace('./' + SRC_DIR + '/', './' + BUILD_DIR + '/'); } +function validateTypeScriptDefs(packageName /*: string */) { + const files = glob.sync( + path.resolve(PACKAGES_DIR, packageName, BUILD_DIR, '**/*.d.ts'), + ); + const compilerOptions = { + ...getTypeScriptCompilerOptions(packageName), + noEmit: true, + skipLibCheck: false, + }; + const program = ts.createProgram(files, compilerOptions); + const emitResult = program.emit(); + + if (emitResult.diagnostics.length) { + for (const diagnostic of emitResult.diagnostics) { + if (diagnostic.file != null) { + let {line, character} = ts.getLineAndCharacterOfPosition( + diagnostic.file, + diagnostic.start, + ); + let message = ts.flattenDiagnosticMessageText( + diagnostic.messageText, + '\n', + ); + console.log( + // $FlowIssue[incompatible-use] Type refined above + `${diagnostic.file.fileName} (${line + 1},${ + character + 1 + }): ${message}`, + ); + } else { + console.log( + ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'), + ); + } + } + + throw new Error( + 'Failing build because TypeScript errors were encountered for ' + + 'generated type definitions.', + ); + } +} + module.exports = { buildFile, getBuildPath, @@ -182,5 +271,6 @@ module.exports = { }; if (require.main === module) { - build(); + // eslint-disable-next-line no-void + void build(); } diff --git a/scripts/build/config.js b/scripts/build/config.js index 854d7bff628e76..a2014995b829d9 100644 --- a/scripts/build/config.js +++ b/scripts/build/config.js @@ -11,57 +11,82 @@ /*:: import type {BabelCoreOptions} from '@babel/core'; +*/ + +const {ModuleResolutionKind} = require('typescript'); +/*:: export type BuildOptions = $ReadOnly<{ + // The target runtime to compile for. target: 'node', + + // Whether to emit Flow definition files (.js.flow) (default: true). + emitFlowDefs?: boolean, + + // Whether to emit TypeScript definition files (.d.ts) (default: false). + emitTypeScriptDefs?: boolean, }>; export type BuildConfig = $ReadOnly<{ + // The packages to include for build and their build options. packages: $ReadOnly<{[packageName: string]: BuildOptions}>, }>; */ -const TARGET_NODE_VERSION = '18'; - +/** + * - BUILD CONFIG - + * + * Add packages here to configure them as part of the monorepo `yarn build` + * setup. These must use a consistent package structure and (today) target + * Node.js packages only. + */ const buildConfig /*: BuildConfig */ = { - // The packages to include for build and their build options packages: { - 'community-cli-plugin': {target: 'node'}, - 'dev-middleware': {target: 'node'}, + 'community-cli-plugin': { + target: 'node', + }, + 'dev-middleware': { + target: 'node', + emitTypeScriptDefs: true, + }, }, }; +const defaultBuildOptions = { + emitFlowDefs: true, + emitTypeScriptDefs: false, +}; + +function getBuildOptions( + packageName /*: $Keys */, +) /*: Required */ { + return { + ...defaultBuildOptions, + ...buildConfig.packages[packageName], + }; +} + function getBabelConfig( packageName /*: $Keys */, ) /*: BabelCoreOptions */ { - const {target} = buildConfig.packages[packageName]; + const {target} = getBuildOptions(packageName); + + switch (target) { + case 'node': + return require('./babel/node.config.js'); + } +} + +function getTypeScriptCompilerOptions( + packageName /*: $Keys */, +) /*: Object */ { + const {target} = getBuildOptions(packageName); switch (target) { case 'node': return { - presets: [ - '@babel/preset-flow', - [ - '@babel/preset-env', - { - targets: { - node: TARGET_NODE_VERSION, - }, - }, - ], - ], - plugins: [ - [ - 'transform-define', - { - 'process.env.BUILD_EXCLUDE_BABEL_REGISTER': true, - }, - ], - [ - 'minify-dead-code-elimination', - {keepFnName: true, keepFnArgs: true, keepClassName: true}, - ], - ], + ...require('@tsconfig/node18/tsconfig.json').compilerOptions, + moduleResolution: ModuleResolutionKind.NodeJs, }; } } @@ -69,4 +94,6 @@ function getBabelConfig( module.exports = { buildConfig, getBabelConfig, + getBuildOptions, + getTypeScriptCompilerOptions, }; diff --git a/yarn.lock b/yarn.lock index f97611334f0014..ff5f1e3217815b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2817,6 +2817,11 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== +"@tsconfig/node18@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node18/-/node18-1.0.1.tgz#ea5b375a9ead6b09ccbd70c3894ea069829ea1bb" + integrity sha512-sNFeK6X2ATlhlvzyH4kKYQlfHXE2f2/wxtB9ClvYXevWpmwkUT7VaSrjIN9E76Qebz8qP5JOJJ9jD3QoD/Z9TA== + "@types/archiver@5.3.2": version "5.3.2" resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.3.2.tgz#a9f0bcb0f0b991400e7766d35f6e19d163bdadcc" @@ -3328,6 +3333,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.5.tgz#e63c5952532306d97c6ea432cee0981f6d2258c7" integrity sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w== +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== + "@typescript-eslint/typescript-estree@5.59.5": version "5.59.5" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz#9b252ce55dd765e972a7a2f99233c439c5101e42" @@ -3363,6 +3373,14 @@ "@typescript-eslint/types" "5.59.5" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@^5.42.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== + dependencies: + "@typescript-eslint/types" "5.62.0" + eslint-visitor-keys "^3.3.0" + "@wdio/config@7.31.1": version "7.31.1" resolved "https://registry.yarnpkg.com/@wdio/config/-/config-7.31.1.tgz#53550a164c970403628525ecdc5e0c3f96a0ff30" @@ -5689,7 +5707,7 @@ esprima@^4.0.0, esprima@~4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2: +esquery@^1.4.0, esquery@^1.4.2: version "1.5.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== @@ -6072,6 +6090,19 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== +flow-api-translator@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/flow-api-translator/-/flow-api-translator-0.15.1.tgz#e7b96b6ce17834687dbd0c7498a9ad393a12e1fb" + integrity sha512-qDXrqPcSw0bkCU17NiZs1jHWZ3mTD3xx//qGLFccA8Jq5sNvlWB0uYRU+w/xMC5/IRw6DROPq6IefCPE0zv5RA== + dependencies: + "@babel/code-frame" "^7.16.0" + "@typescript-eslint/visitor-keys" "^5.42.0" + flow-enums-runtime "^0.0.6" + hermes-eslint "0.15.1" + hermes-estree "0.15.1" + hermes-parser "0.15.1" + hermes-transform "0.15.1" + flow-bin@^0.214.0: version "0.214.0" resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.214.0.tgz#3ace7984a69309392e056f96cf3bf8623fa93d1c" @@ -6548,6 +6579,15 @@ hermes-eslint@0.15.0: hermes-estree "0.15.0" hermes-parser "0.15.0" +hermes-eslint@0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.15.1.tgz#c5919a6fdbd151febc3d5ed8ff17e5433913528c" + integrity sha512-ArfT3oASsYOkCa29GOw34GR+kpHXqrhhYgXDadK3daJBejrMPbGlUbBTzTlGBuz1CGLxxdC5lwwv3OegPJzfDA== + dependencies: + esrecurse "^4.3.0" + hermes-estree "0.15.1" + hermes-parser "0.15.1" + hermes-estree@0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.14.0.tgz#c663eea1400980802283338a09d0087c448729e7" @@ -6558,6 +6598,11 @@ hermes-estree@0.15.0: resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.15.0.tgz#e32f6210ab18c7b705bdcb375f7700f2db15d6ba" integrity sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ== +hermes-estree@0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.15.1.tgz#d06d4ddf87e91857b0130a083a9d7696d7aec61f" + integrity sha512-XrQH+GATG/8DYbzlrVs6Vf/EDxLhYEHXvzt/Xve4b/NXXpsNLDN8bdBEKp5z0XeOMoL1XMEexxIIf1a5bH6kYA== + hermes-parser@0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.14.0.tgz#edb2e7172fce996d2c8bbba250d140b70cc1aaaf" @@ -6572,6 +6617,13 @@ hermes-parser@0.15.0: dependencies: hermes-estree "0.15.0" +hermes-parser@0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.15.1.tgz#f02587be85228b22841d50f6839ae42a308e5100" + integrity sha512-38Re105dr4UZ0/EPRApWxtIOWWynQpdOYWO+7nFO8ADd2mXdaHKMCFAxIjkqACa1GLrAtrXqqaJdUYHi/QUbkA== + dependencies: + hermes-estree "0.15.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" @@ -6579,6 +6631,18 @@ hermes-profile-transformer@^0.0.6: dependencies: source-map "^0.7.3" +hermes-transform@0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/hermes-transform/-/hermes-transform-0.15.1.tgz#934f4b6e93029b4552b60a837c5c4506f10c94f6" + integrity sha512-f2mT55uL7y7WcQ6oUNXMPI4ehs1j85Ox1eVuUSQWGFzIfPKM0xCcHRd6sLOAKTI7LfUnlGxKhTWwPIooP9fi1A== + dependencies: + "@babel/code-frame" "^7.16.0" + esquery "^1.4.0" + flow-enums-runtime "^0.0.6" + hermes-eslint "0.15.1" + hermes-estree "0.15.1" + hermes-parser "0.15.1" + homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"