diff --git a/.github/workflow-scripts/__tests__/createDraftRelease-test.js b/.github/workflow-scripts/__tests__/createDraftRelease-test.js index 77901d4df0999e..587e48e6d320bc 100644 --- a/.github/workflow-scripts/__tests__/createDraftRelease-test.js +++ b/.github/workflow-scripts/__tests__/createDraftRelease-test.js @@ -188,6 +188,7 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/ status: 201, json: () => Promise.resolve({ + id: 1, html_url: 'https://github.com/facebook/react-native/releases/tag/v0.77.1', }), @@ -208,9 +209,11 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/ body: fetchBody, }, ); - expect(response).toEqual( - 'https://github.com/facebook/react-native/releases/tag/v0.77.1', - ); + expect(response).toEqual({ + id: 1, + html_url: + 'https://github.com/facebook/react-native/releases/tag/v0.77.1', + }); }); it('creates a draft release for prerelease on GitHub', async () => { @@ -238,6 +241,7 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/ status: 201, json: () => Promise.resolve({ + id: 1, html_url: 'https://github.com/facebook/react-native/releases/tag/v0.77.1', }), @@ -258,9 +262,11 @@ View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/ body: fetchBody, }, ); - expect(response).toEqual( - 'https://github.com/facebook/react-native/releases/tag/v0.77.1', - ); + expect(response).toEqual({ + id: 1, + html_url: + 'https://github.com/facebook/react-native/releases/tag/v0.77.1', + }); }); it('throws if the post failes', async () => { diff --git a/.github/workflow-scripts/createDraftRelease.js b/.github/workflow-scripts/createDraftRelease.js index f8737c3cbfda4c..4626f90fb9b041 100644 --- a/.github/workflow-scripts/createDraftRelease.js +++ b/.github/workflow-scripts/createDraftRelease.js @@ -101,7 +101,11 @@ async function _createDraftReleaseOnGitHub(version, body, latest, token) { } const data = await response.json(); - return data.html_url; + const {html_url, id} = data; + return { + html_url, + id, + }; } function moveToChangelogBranch(version) { @@ -124,7 +128,7 @@ async function createDraftRelease(version, latest, token) { latest, token, ); - log(`Created draft release: ${release}`); + log(`Created draft release: ${release.html_url}`); } module.exports = { diff --git a/.github/workflows/create-draft-release.yml b/.github/workflows/create-draft-release.yml index d3b89dba90d805..6473263e8fb690 100644 --- a/.github/workflows/create-draft-release.yml +++ b/.github/workflows/create-draft-release.yml @@ -2,6 +2,7 @@ name: Create Draft Release on: workflow_call: + pull_request: jobs: create-draft-release: @@ -21,9 +22,24 @@ jobs: git config --local user.name "React Native Bot" - name: Create draft release uses: actions/github-script@v6 + id: create-draft-release with: script: | const {createDraftRelease} = require('./.github/workflow-scripts/createDraftRelease.js'); const version = '${{ github.ref_name }}'; const {isLatest} = require('./.github/workflow-scripts/publishTemplate.js'); - await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}'); + return (await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}')).id; + result-encoding: string + - name: Upload release assets for DotSlash + uses: actions/github-script@v6 + env: + RELEASE_ID: ${{ steps.create-draft-release.outputs.result }} + with: + script: | + const {uploadReleaseAssetsForDotSlash} = require('./scripts/releases/upload-release-assets-for-dotslash.js'); + const version = '${{ github.ref_name }}'; + await uploadReleaseAssetsForDotSlash({ + version, + token: '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}', + releaseId: process.env.RELEASE_ID, + }); diff --git a/package.json b/package.json index 03d3261c8ad2de..73dc59fe81abcf 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,10 @@ "@electron/packager": "^18.3.6", "@jest/create-cache-key-function": "^29.7.0", "@microsoft/api-extractor": "^7.52.2", - "@react-native/metro-babel-transformer": "0.82.0-main", - "@react-native/metro-config": "0.82.0-main", + "@motizilberman/dotslash": "0.5.7-1754587239403", + "@octokit/rest": "^22.0.0", + "@react-native/metro-babel-transformer": "0.82.0-20250807-1752", + "@react-native/metro-config": "0.82.0-20250807-1752", "@tsconfig/node22": "22.0.2", "@types/react": "^19.1.0", "@typescript-eslint/parser": "^8.36.0", @@ -93,6 +95,7 @@ "jest-diff": "^29.7.0", "jest-junit": "^10.0.0", "jest-snapshot": "^29.7.0", + "jsonc-parser": "^3.3.1", "markdownlint-cli2": "^0.17.2", "markdownlint-rule-relative-links": "^3.0.0", "memfs": "^4.7.7", diff --git a/packages/assets/package.json b/packages/assets/package.json index aff74ac9732b96..e3b2290bda3c5c 100644 --- a/packages/assets/package.json +++ b/packages/assets/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/assets-registry", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Asset support code for React Native.", "license": "MIT", "repository": { diff --git a/packages/babel-plugin-codegen/package.json b/packages/babel-plugin-codegen/package.json index 6af39526dbed5f..6a4afa159b6588 100644 --- a/packages/babel-plugin-codegen/package.json +++ b/packages/babel-plugin-codegen/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/babel-plugin-codegen", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Babel plugin to generate native module and view manager code for React Native.", "license": "MIT", "repository": { @@ -26,7 +26,7 @@ ], "dependencies": { "@babel/traverse": "^7.25.3", - "@react-native/codegen": "0.82.0-main" + "@react-native/codegen": "0.82.0-20250807-1752" }, "devDependencies": { "@babel/core": "^7.25.2" diff --git a/packages/community-cli-plugin/package.json b/packages/community-cli-plugin/package.json index 5d070269c3eaab..d2bf017f798019 100644 --- a/packages/community-cli-plugin/package.json +++ b/packages/community-cli-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/community-cli-plugin", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Core CLI commands for React Native", "keywords": [ "react-native", @@ -22,7 +22,7 @@ "dist" ], "dependencies": { - "@react-native/dev-middleware": "0.82.0-main", + "@react-native/dev-middleware": "0.82.0-20250807-1752", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", diff --git a/packages/core-cli-utils/package.json b/packages/core-cli-utils/package.json index 601eb124a5da8a..e05aaba98a3ce5 100644 --- a/packages/core-cli-utils/package.json +++ b/packages/core-cli-utils/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/core-cli-utils", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "React Native CLI library for Frameworks to build on", "license": "MIT", "main": "./src/index.flow.js", diff --git a/packages/debugger-frontend/package.json b/packages/debugger-frontend/package.json index 1475dd77753fc3..174cfdcb54e89f 100644 --- a/packages/debugger-frontend/package.json +++ b/packages/debugger-frontend/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/debugger-frontend", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Debugger frontend for React Native based on Chrome DevTools", "keywords": [ "react-native", diff --git a/packages/debugger-shell/bin/react-native-devtools b/packages/debugger-shell/bin/react-native-devtools index a1fc11d8581040..4b0933e10558a4 100755 --- a/packages/debugger-shell/bin/react-native-devtools +++ b/packages/debugger-shell/bin/react-native-devtools @@ -1,6 +1,6 @@ #!/usr/bin/env dotslash -// @generated SignedSource<<686df5695b32a90cd465412d979a1a3f>> +// @generated SignedSource<<774a1f20216bb2dc2e91ffb06d23c3af>> { @@ -11,6 +11,9 @@ "hash": "sha256", "digest": "c22f7d5e029357f05055ce7c56cc284a0d441d558e103a7b7ebae118c67d0b95", "providers": [ + { + "url": "https://github.com/facebook/react-native/releases/download/v0.82.0-20250807-1752/React.Native.DevTools-linux-aarch64.tar.gz" + }, { "type": "http", "url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPRilWDJV8xyKEv9lqYn7Hf2kyZg6nqW8KctGZCXsU95lS_MTFyAmEULrB3J6hGCjqBY2Zl-uq_FjERAIgzbZFWX2eceacTbutBSOKEj6QTZzkVN_L1zPh2lGh24x29MHpkwUzw4E-kAXV43f-11QxqD7orI1QicyOnsmUqeRNKE_QjM9rNRsw6iE8" @@ -24,6 +27,9 @@ "hash": "sha256", "digest": "d749aee18d6c969f033511ed631b439c578068cc20786974bc0ee707c6c2f177", "providers": [ + { + "url": "https://github.com/facebook/react-native/releases/download/v0.82.0-20250807-1752/React.Native.DevTools-linux-x86_64.tar.gz" + }, { "type": "http", "url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQP8NAAXjHJ-9NJThip1nnmVim4yiS1tdYAXmWl2Remiluq5f13nXA8YEadsmGRLWxXz2WJouHXSK47ea4a30fxewyKeTt0niFn3T-lr_91m3Ve5ZS-FOZ_9CRVCkv5zC-Z1FlXJGOnphfWetIU10Pw9tho3IzjdSNlXle0XTrkJ2AyKSl4cKPaX" @@ -37,6 +43,9 @@ "hash": "sha256", "digest": "dc4a6cfa3d2d8646db8793ef497e43ad72be54bb14ed96345d059880ff72ce1e", "providers": [ + { + "url": "https://github.com/facebook/react-native/releases/download/v0.82.0-20250807-1752/React.Native.DevTools-macos-aarch64.tar.gz" + }, { "type": "http", "url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPuZx9G4h30mUDM0hZ8y74LbzAi7-S6jnOqq8uyfDdIptLwIgpb8CKB8F2tduvaBFMGd7obwXd2NVy01r6XKVdgAK5-QTp8PYUPUE7VSCi6QAqobXcQ2uq_lY-jgyj8XkV4Ua4gA6KR609Bmh-beSTOrSqMymqVodaGqoGjB_9jVwfD99_PfFlex-Ta" @@ -50,6 +59,9 @@ "hash": "sha256", "digest": "74178859ce6a1c26c32055e192b1b123822c76c827ea86a6dfdb5463b89b1ace", "providers": [ + { + "url": "https://github.com/facebook/react-native/releases/download/v0.82.0-20250807-1752/React.Native.DevTools-macos-x86_64.tar.gz" + }, { "type": "http", "url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN6DjGhr8_L7N_cwrh8pi3cfNcbn9dot_QQpgwe3Vv-780FDgi6JUeMvbo_wbFoT2rogxfHZ0-NbXbKdWYwhGUoGeQuikT57QnVMOYuPUTjlQUgYy0Ng9XPhq3iSEYwlMV1XsUJuPFRUg-hIHcgaaA55JoTLXZ1fLYydhHnmgRxGHc4pxaHvSpTtQ" diff --git a/packages/debugger-shell/package.json b/packages/debugger-shell/package.json index d95afdeeebdd03..d441f840a5232d 100644 --- a/packages/debugger-shell/package.json +++ b/packages/debugger-shell/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/debugger-shell", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Experimental debugger shell for React Native for use with @react-native/debugger-frontend", "keywords": [ "react-native", diff --git a/packages/dev-middleware/package.json b/packages/dev-middleware/package.json index 2183969a85090a..ed6f8ee47905ed 100644 --- a/packages/dev-middleware/package.json +++ b/packages/dev-middleware/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/dev-middleware", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Dev server middleware for React Native", "keywords": [ "react-native", @@ -23,7 +23,7 @@ ], "dependencies": { "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.82.0-main", + "@react-native/debugger-frontend": "0.82.0-20250807-1752", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", diff --git a/packages/eslint-config-react-native/package.json b/packages/eslint-config-react-native/package.json index 2cf4c8ab56a805..e928811262adc2 100644 --- a/packages/eslint-config-react-native/package.json +++ b/packages/eslint-config-react-native/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/eslint-config", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "ESLint config for React Native", "license": "MIT", "repository": { @@ -22,7 +22,7 @@ "dependencies": { "@babel/core": "^7.25.2", "@babel/eslint-parser": "^7.25.1", - "@react-native/eslint-plugin": "0.82.0-main", + "@react-native/eslint-plugin": "0.82.0-20250807-1752", "@typescript-eslint/eslint-plugin": "^8.36.0", "@typescript-eslint/parser": "^8.36.0", "eslint-config-prettier": "^8.5.0", diff --git a/packages/eslint-plugin-react-native/package.json b/packages/eslint-plugin-react-native/package.json index 371511f0ef3c35..dd5f1aa57110f0 100644 --- a/packages/eslint-plugin-react-native/package.json +++ b/packages/eslint-plugin-react-native/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/eslint-plugin", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "ESLint rules for @react-native/eslint-config", "license": "MIT", "repository": { diff --git a/packages/eslint-plugin-specs/package.json b/packages/eslint-plugin-specs/package.json index a5c14cf72bd88a..92c9c54bbaa458 100644 --- a/packages/eslint-plugin-specs/package.json +++ b/packages/eslint-plugin-specs/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/eslint-plugin-specs", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "ESLint rules to validate NativeModule and Component Specs", "license": "MIT", "repository": { @@ -26,7 +26,7 @@ "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-transform-flow-strip-types": "^7.25.2", - "@react-native/codegen": "0.82.0-main", + "@react-native/codegen": "0.82.0-20250807-1752", "make-dir": "^2.1.0", "pirates": "^4.0.1", "source-map-support": "0.5.0" diff --git a/packages/gradle-plugin/package.json b/packages/gradle-plugin/package.json index bb4d12c2f2572c..ab94c8bffae75a 100644 --- a/packages/gradle-plugin/package.json +++ b/packages/gradle-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/gradle-plugin", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Gradle Plugin for React Native", "license": "MIT", "repository": { diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index 094d41a7a7a83e..9bebe0f143b204 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/metro-config", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Metro configuration for React Native.", "license": "MIT", "repository": { @@ -26,8 +26,8 @@ "dist" ], "dependencies": { - "@react-native/js-polyfills": "0.82.0-main", - "@react-native/metro-babel-transformer": "0.82.0-main", + "@react-native/js-polyfills": "0.82.0-20250807-1752", + "@react-native/metro-babel-transformer": "0.82.0-20250807-1752", "metro-config": "^0.83.1", "metro-runtime": "^0.83.1" } diff --git a/packages/new-app-screen/package.json b/packages/new-app-screen/package.json index d1926d11577487..45b849d2d25e8d 100644 --- a/packages/new-app-screen/package.json +++ b/packages/new-app-screen/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/new-app-screen", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "NewAppScreen component for React Native", "keywords": [ "react-native" diff --git a/packages/normalize-color/package.json b/packages/normalize-color/package.json index d6a7de133ca6df..33eb022142a00b 100644 --- a/packages/normalize-color/package.json +++ b/packages/normalize-color/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/normalize-colors", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Color normalization for React Native.", "license": "MIT", "repository": { diff --git a/packages/polyfills/package.json b/packages/polyfills/package.json index 355da1286ac651..3df56d430da643 100644 --- a/packages/polyfills/package.json +++ b/packages/polyfills/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/js-polyfills", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Polyfills for React Native.", "license": "MIT", "repository": { diff --git a/packages/react-native-babel-preset/package.json b/packages/react-native-babel-preset/package.json index cf40f7e2833dfd..daaee3d252b09a 100644 --- a/packages/react-native-babel-preset/package.json +++ b/packages/react-native-babel-preset/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/babel-preset", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Babel preset for React Native applications", "repository": { "type": "git", @@ -66,7 +66,7 @@ "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", - "@react-native/babel-plugin-codegen": "0.82.0-main", + "@react-native/babel-plugin-codegen": "0.82.0-20250807-1752", "babel-plugin-syntax-hermes-parser": "0.30.0", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" diff --git a/packages/react-native-babel-transformer/package.json b/packages/react-native-babel-transformer/package.json index be35066c3e2470..839db02915366f 100644 --- a/packages/react-native-babel-transformer/package.json +++ b/packages/react-native-babel-transformer/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/metro-babel-transformer", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Babel transformer for React Native applications.", "repository": { "type": "git", @@ -27,7 +27,7 @@ ], "dependencies": { "@babel/core": "^7.25.2", - "@react-native/babel-preset": "0.82.0-main", + "@react-native/babel-preset": "0.82.0-20250807-1752", "hermes-parser": "0.30.0", "nullthrows": "^1.1.1" }, diff --git a/packages/react-native-codegen/package.json b/packages/react-native-codegen/package.json index d4f0b104d34792..849880c55fd2a7 100644 --- a/packages/react-native-codegen/package.json +++ b/packages/react-native-codegen/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/codegen", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Code generation tools for React Native", "license": "MIT", "repository": { diff --git a/packages/react-native-compatibility-check/package.json b/packages/react-native-compatibility-check/package.json index 6d8f07fa1c625d..937d17f58e6eaf 100644 --- a/packages/react-native-compatibility-check/package.json +++ b/packages/react-native-compatibility-check/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/compatibility-check", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Check a React Native app's boundary between JS and Native for incompatibilities", "license": "MIT", "repository": { @@ -29,7 +29,7 @@ "dist" ], "dependencies": { - "@react-native/codegen": "0.82.0-main" + "@react-native/codegen": "0.82.0-20250807-1752" }, "devDependencies": { "flow-remove-types": "^2.237.2", diff --git a/packages/react-native-popup-menu-android/package.json b/packages/react-native-popup-menu-android/package.json index e34b574f4cac96..a4bb10687b73e8 100644 --- a/packages/react-native-popup-menu-android/package.json +++ b/packages/react-native-popup-menu-android/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/popup-menu-android", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "PopupMenu for the Android platform", "main": "index.js", "files": [ @@ -21,7 +21,7 @@ }, "license": "MIT", "devDependencies": { - "@react-native/codegen": "0.82.0-main" + "@react-native/codegen": "0.82.0-20250807-1752" }, "peerDependencies": { "@types/react": "^19.1.0", diff --git a/packages/react-native/Libraries/Core/ReactNativeVersion.js b/packages/react-native/Libraries/Core/ReactNativeVersion.js index 1ff12f563e621a..f753b0c4e4a0b6 100644 --- a/packages/react-native/Libraries/Core/ReactNativeVersion.js +++ b/packages/react-native/Libraries/Core/ReactNativeVersion.js @@ -26,10 +26,10 @@ * ``` */ export default class ReactNativeVersion { - static major: number = 1000; - static minor: number = 0; + static major: number = 0; + static minor: number = 82; static patch: number = 0; - static prerelease: string | null = null; + static prerelease: string | null = '20250807-1752'; static getVersionString(): string { return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`; diff --git a/packages/react-native/React/Base/RCTVersion.m b/packages/react-native/React/Base/RCTVersion.m index 69ce4f75320e63..12aecb5ff5827d 100644 --- a/packages/react-native/React/Base/RCTVersion.m +++ b/packages/react-native/React/Base/RCTVersion.m @@ -21,10 +21,10 @@ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^(void){ __rnVersion = @{ - RCTVersionMajor: @(1000), - RCTVersionMinor: @(0), + RCTVersionMajor: @(0), + RCTVersionMinor: @(82), RCTVersionPatch: @(0), - RCTVersionPrerelease: [NSNull null], + RCTVersionPrerelease: @"20250807-1752", }; }); return __rnVersion; diff --git a/packages/react-native/ReactAndroid/gradle.properties b/packages/react-native/ReactAndroid/gradle.properties index 7c0c467db7a633..619a07d0e80ce0 100644 --- a/packages/react-native/ReactAndroid/gradle.properties +++ b/packages/react-native/ReactAndroid/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=1000.0.0 +VERSION_NAME=0.82.0-20250807-1752 react.internal.publishingGroup=com.facebook.react android.useAndroidX=true diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt index 2405d32ce682d5..10a0e0ac8eb652 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt @@ -12,9 +12,9 @@ package com.facebook.react.modules.systeminfo public object ReactNativeVersion { @JvmField public val VERSION: Map = mapOf( - "major" to 1000, - "minor" to 0, + "major" to 0, + "minor" to 82, "patch" to 0, - "prerelease" to null + "prerelease" to "20250807-1752" ) } diff --git a/packages/react-native/ReactCommon/cxxreact/ReactNativeVersion.h b/packages/react-native/ReactCommon/cxxreact/ReactNativeVersion.h index 0c876d971a62c4..b48bc69ad398a2 100644 --- a/packages/react-native/ReactCommon/cxxreact/ReactNativeVersion.h +++ b/packages/react-native/ReactCommon/cxxreact/ReactNativeVersion.h @@ -12,17 +12,17 @@ #include #include -#define REACT_NATIVE_VERSION_MAJOR 1000 -#define REACT_NATIVE_VERSION_MINOR 0 +#define REACT_NATIVE_VERSION_MAJOR 0 +#define REACT_NATIVE_VERSION_MINOR 82 #define REACT_NATIVE_VERSION_PATCH 0 namespace facebook::react { constexpr struct { - int32_t Major = 1000; - int32_t Minor = 0; + int32_t Major = 0; + int32_t Minor = 82; int32_t Patch = 0; - std::string_view Prerelease = ""; + std::string_view Prerelease = "20250807-1752"; } ReactNativeVersion; } // namespace facebook::react diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 0e62e94a992df6..9eb85aa0b2fa59 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -1,6 +1,6 @@ { "name": "react-native", - "version": "1000.0.0", + "version": "0.82.0-20250807-1752", "description": "A framework for building native apps using React", "license": "MIT", "repository": { @@ -162,13 +162,13 @@ }, "dependencies": { "@jest/create-cache-key-function": "^29.7.0", - "@react-native/assets-registry": "0.82.0-main", - "@react-native/codegen": "0.82.0-main", - "@react-native/community-cli-plugin": "0.82.0-main", - "@react-native/gradle-plugin": "0.82.0-main", - "@react-native/js-polyfills": "0.82.0-main", - "@react-native/normalize-colors": "0.82.0-main", - "@react-native/virtualized-lists": "0.82.0-main", + "@react-native/assets-registry": "0.82.0-20250807-1752", + "@react-native/codegen": "0.82.0-20250807-1752", + "@react-native/community-cli-plugin": "0.82.0-20250807-1752", + "@react-native/gradle-plugin": "0.82.0-20250807-1752", + "@react-native/js-polyfills": "0.82.0-20250807-1752", + "@react-native/normalize-colors": "0.82.0-20250807-1752", + "@react-native/virtualized-lists": "0.82.0-20250807-1752", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", diff --git a/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap b/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap index cd534fef71e943..b05cc23828832e 100644 --- a/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap +++ b/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap @@ -361,7 +361,7 @@ exports[`execute test-app "ReactAppDependencyProvider.podspec" should match snap # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -version = \\"1000.0.0\\" +version = \\"0.82.0-20250807-1752\\" source = { :git => 'https://github.com/facebook/react-native.git' } if version == '1000.0.0' # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. @@ -399,7 +399,7 @@ exports[`execute test-app "ReactCodegen.podspec" should match snapshot 1`] = ` # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -version = \\"1000.0.0\\" +version = \\"0.82.0-20250807-1752\\" source = { :git => 'https://github.com/facebook/react-native.git' } if version == '1000.0.0' # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. @@ -839,7 +839,7 @@ exports[`execute test-app-legacy "ReactAppDependencyProvider.podspec" should mat # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -version = \\"1000.0.0\\" +version = \\"0.82.0-20250807-1752\\" source = { :git => 'https://github.com/facebook/react-native.git' } if version == '1000.0.0' # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. @@ -877,7 +877,7 @@ exports[`execute test-app-legacy "ReactCodegen.podspec" should match snapshot 1` # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -version = \\"1000.0.0\\" +version = \\"0.82.0-20250807-1752\\" source = { :git => 'https://github.com/facebook/react-native.git' } if version == '1000.0.0' # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. @@ -982,4 +982,4 @@ SCRIPT end " -`; +`; \ No newline at end of file diff --git a/packages/rn-tester/package.json b/packages/rn-tester/package.json index 92e52bdf14faaa..992ee0d1fd4a54 100644 --- a/packages/rn-tester/package.json +++ b/packages/rn-tester/package.json @@ -26,8 +26,8 @@ "e2e-test-ios": "./scripts/maestro-test-ios.sh" }, "dependencies": { - "@react-native/new-app-screen": "0.82.0-main", - "@react-native/popup-menu-android": "0.82.0-main", + "@react-native/new-app-screen": "0.82.0-20250807-1752", + "@react-native/popup-menu-android": "0.82.0-20250807-1752", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "nullthrows": "^1.1.1" diff --git a/packages/typescript-config/package.json b/packages/typescript-config/package.json index a00cd1a2fe912e..475d2064f02c3b 100644 --- a/packages/typescript-config/package.json +++ b/packages/typescript-config/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/typescript-config", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Default TypeScript configuration for React Native apps", "license": "MIT", "repository": { diff --git a/packages/virtualized-lists/package.json b/packages/virtualized-lists/package.json index f5d6eb2d2c82e4..6f154647ee5535 100644 --- a/packages/virtualized-lists/package.json +++ b/packages/virtualized-lists/package.json @@ -1,6 +1,6 @@ { "name": "@react-native/virtualized-lists", - "version": "0.82.0-main", + "version": "0.82.0-20250807-1752", "description": "Virtualized lists for React Native.", "license": "MIT", "repository": { diff --git a/private/helloworld/package.json b/private/helloworld/package.json index 757495928cacc0..d0ac06ed7b18d6 100644 --- a/private/helloworld/package.json +++ b/private/helloworld/package.json @@ -13,17 +13,17 @@ }, "dependencies": { "react": "19.1.1", - "react-native": "1000.0.0" + "react-native": "0.82.0-20250807-1752" }, "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "@babel/runtime": "^7.25.0", - "@react-native/babel-preset": "0.82.0-main", - "@react-native/core-cli-utils": "0.82.0-main", - "@react-native/eslint-config": "0.82.0-main", - "@react-native/metro-config": "0.82.0-main", - "@react-native/typescript-config": "0.82.0-main", + "@react-native/babel-preset": "0.82.0-20250807-1752", + "@react-native/core-cli-utils": "0.82.0-20250807-1752", + "@react-native/eslint-config": "0.82.0-20250807-1752", + "@react-native/metro-config": "0.82.0-20250807-1752", + "@react-native/typescript-config": "0.82.0-20250807-1752", "@types/jest": "^29.5.14", "commander": "^12.0.0", "eslint": "^8.19.0", diff --git a/private/react-native-codegen-typescript-test/package.json b/private/react-native-codegen-typescript-test/package.json index 1270bd5aafd136..6b475e80586179 100644 --- a/private/react-native-codegen-typescript-test/package.json +++ b/private/react-native-codegen-typescript-test/package.json @@ -13,7 +13,7 @@ "prepare": "yarn run build" }, "dependencies": { - "@react-native/codegen": "0.82.0-main" + "@react-native/codegen": "0.82.0-20250807-1752" }, "devDependencies": { "@babel/core": "^7.25.2", diff --git a/scripts/releases/create-release-commit.js b/scripts/releases/create-release-commit.js index 50d2f8a8acd99d..77c5d30a7e35a3 100644 --- a/scripts/releases/create-release-commit.js +++ b/scripts/releases/create-release-commit.js @@ -10,6 +10,7 @@ const {setVersion} = require('../releases/set-version'); const {getBranchName} = require('../releases/utils/scm-utils'); +const {writeReleaseAssetUrlsToDotSlashFiles} = require('../releases/write-dotslash-release-asset-urls'); const {parseVersion} = require('./utils/version-utils'); const {execSync} = require('child_process'); const yargs = require('yargs'); @@ -49,6 +50,9 @@ async function main() { console.info('Setting version for monorepo packages and react-native'); await setVersion(version, false); // version, skip-react-native + console.info('Writing release asset URLs to DotSlash files'); + await writeReleaseAssetUrlsToDotSlashFiles(version); + if (dryRun) { console.info('Running in dry-run mode, skipping git commit'); console.info( diff --git a/scripts/releases/upload-release-assets-for-dotslash.js b/scripts/releases/upload-release-assets-for-dotslash.js new file mode 100644 index 00000000000000..16914ac803c3bf --- /dev/null +++ b/scripts/releases/upload-release-assets-for-dotslash.js @@ -0,0 +1,193 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +const {validateAndParseDotSlashFile} = require('./utils/dotslash-utils'); +const {REPO_ROOT} = require('../shared/consts'); +const {parseArgs} = require('util'); +const path = require('path'); +const {Octokit} = require('@octokit/rest'); +const { + FIRST_PARTY_DOTSLASH_FILES, +} = require('./write-dotslash-release-asset-urls'); + +const config = { + allowPositionals: true, + options: { + token: {type: 'string'}, + releaseId: {type: 'string'}, + force: {type: 'boolean', default: false}, + dryRun: {type: 'boolean', default: false}, + help: {type: 'boolean'}, + }, +}; + +async function main() { + const { + positionals: [version], + values: {help, token, releaseId, force, dryRun}, + /* $FlowFixMe[incompatible-call] Natural Inference rollout. See + * https://fburl.com/workplace/6291gfvu */ + } = parseArgs(config); + + if (help) { + console.log(` + Usage: node ./scripts/releases/upload-release-assets-for-dotslash.js --release_id --token [--force] + + Scans first-party DotSlash files in the repo for URLs referencing assets of + an upcoming release, and uploads the actual assets to the GitHub release + identified by the given release ID. + + If run with --force, the script will overwrite any assets that happen to + already exist at the given URLs. This is useful for retrying failed or + corrupted uploads. +`); + return; + } + + if (version == null) { + throw new Error('Missing version argument'); + } + + await uploadReleaseAssetsForDotSlash({ + version, + token, + releaseId, + force, + dryRun, + }); +} + +async function uploadReleaseAssetsForDotSlash( + {version, token, releaseId, force = false, dryRun = false} /*: { + version: string, + token: string, + releaseId: string, + force?: boolean, + dryRun?: boolean, + } */, +) /*: Promise */ { + const releaseTag = `v${version}`; + const releaseAssetPrefix = `https://github.com/facebook/react-native/releases/download/${encodeURIComponent(releaseTag)}/`; + const octokit = new Octokit({auth: token}); + const existingAssets = await octokit.repos.listReleaseAssets({ + owner: 'facebook', + repo: 'react-native', + release_id: releaseId, + }); + const existingAssetsByName = new Map( + existingAssets.data.map(asset => [asset.name, asset]), + ); + for (const filename of FIRST_PARTY_DOTSLASH_FILES) { + const fullPath = path.join(REPO_ROOT, filename); + console.log(`Uploading assets for ${filename}...`); + const uploadPromises = []; + await processDotSlashFileInPlace( + fullPath, + ( + providers, + // Ignore _suggestedFilename in favour of reading the actual asset URLs + _suggestedFilename, + ) => { + let upstreamUrl, targetReleaseAssetInfo; + for (const provider of providers) { + if (provider.type != null && provider.type !== 'http') { + continue; + } + const url = provider.url; + if (url.startsWith(releaseAssetPrefix)) { + const name = decodeURIComponent( + url.slice(releaseAssetPrefix.length), + ); + targetReleaseAssetInfo = {name, url}; + } else { + upstreamUrl = url; + } + if (upstreamUrl != null && targetReleaseAssetInfo != null) { + break; + } + } + if (targetReleaseAssetInfo == null) { + // This DotSlash providers array does not reference any relevant release asset URLs, so we can ignore it. + return; + } + if (upstreamUrl == null) { + throw new Error( + `No upstream URL found for release asset ${targetReleaseAssetInfo.name}`, + ); + } + uploadPromises.push( + (async () => { + if (existingAssetsByName.has(targetReleaseAssetInfo.name)) { + if (!force) { + console.log( + `[${targetReleaseAssetInfo.name}] Skipping existing release asset...`, + ); + return; + } + if (dryRun) { + console.log( + `[${targetReleaseAssetInfo.name}] Dry run: Not deleting existing release asset.`, + ); + } else { + console.log( + `[${targetReleaseAssetInfo.name}] Deleting existing release asset...`, + ); + await octokit.repos.deleteReleaseAsset({ + owner: 'facebook', + repo: 'react-native', + asset_id: existingAssetsByName.get( + targetReleaseAssetInfo.name, + ).id, + }); + } + } + console.log( + `[${targetReleaseAssetInfo.name}] Downloading from ${upstreamUrl}...`, + ); + const response = await fetch(upstreamUrl); + const data = await response.buffer(); + const contentType = response.headers.get('content-type'); + if (dryRun) { + console.log( + `[${targetReleaseAssetInfo.name}] Dry run: Not uploading to release.`, + ); + return; + } else { + console.log( + `[${targetReleaseAssetInfo.name}] Uploading to release...`, + ); + await octokit.repos.uploadReleaseAsset({ + owner: 'facebook', + repo: 'react-native', + release_id: releaseId, + name: targetReleaseAssetInfo.name, + data, + headers: { + 'content-type': contentType, + }, + }); + } + })(), + ); + }, + ); + await Promise.all(uploadPromises); + } +} + +module.exports = { + uploadReleaseAssetsForDotSlash, +}; + +if (require.main === module) { + void main(); +} diff --git a/scripts/releases/utils/__tests__/__snapshots__/dotslash-utils-test.js.snap b/scripts/releases/utils/__tests__/__snapshots__/dotslash-utils-test.js.snap new file mode 100644 index 00000000000000..5cfed64c202fd3 --- /dev/null +++ b/scripts/releases/utils/__tests__/__snapshots__/dotslash-utils-test.js.snap @@ -0,0 +1,84 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`processDotSlashFileInPlace comments, multiple platforms, providers + replacement: contents after processing 1`] = ` +"#!/usr/bin/env dotslash +// Top-level comment +{ + \\"name\\": \\"test\\", + \\"platforms\\": { + // Comment on linux-x86_64 + \\"linux-x86_64\\": { + \\"size\\": 0, + \\"hash\\": \\"sha256\\", + \\"digest\\": \\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\\", + \\"providers\\": [ + { + \\"url\\": \\"https://example.com/replaced/test-linux-x86_64.tar.gz\\" + } + ], + \\"format\\": \\"tar.gz\\", + \\"path\\": \\"bar\\" + }, + // Comment on macos-aarch64 + \\"macos-aarch64\\": { + \\"size\\": 0, + \\"hash\\": \\"sha256\\", + \\"digest\\": \\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\\", + \\"providers\\": [ + { + \\"url\\": \\"https://primary.example.com/foo-mac.zip\\", + \\"weight\\": 3 + }, + { + \\"url\\": \\"https://mirror1.example.com/foo-mac.zip\\", + \\"weight\\": 1 + }, + { + \\"url\\": \\"https://example.com/added/test-macos-aarch64.zip\\" + } + ], + \\"format\\": \\"zip\\", + \\"path\\": \\"bar\\", + } + } +}" +`; + +exports[`processDotSlashFileInPlace comments, multiple platforms, providers + replacement: transformProviders calls 1`] = ` +Array [ + Array [ + Array [ + Object { + "url": "https://primary.example.com/foo-linux.tar.gz", + "weight": 3, + }, + Object { + "url": "https://mirror1.example.com/foo-linux.tar.gz", + "weight": 1, + }, + Object { + "url": "https://mirror2.example.com/foo-linux.tar.gz", + "weight": 1, + }, + Object { + "url": "https://mirror3.example.com/foo-linux.tar.gz", + "weight": 1, + }, + ], + "test-linux-x86_64.tar.gz", + ], + Array [ + Array [ + Object { + "url": "https://primary.example.com/foo-mac.zip", + "weight": 3, + }, + Object { + "url": "https://mirror1.example.com/foo-mac.zip", + "weight": 1, + }, + ], + "test-macos-aarch64.zip", + ], +] +`; diff --git a/scripts/releases/utils/__tests__/dotslash-utils-test.js b/scripts/releases/utils/__tests__/dotslash-utils-test.js new file mode 100644 index 00000000000000..a31092942ca3ed --- /dev/null +++ b/scripts/releases/utils/__tests__/dotslash-utils-test.js @@ -0,0 +1,174 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +const fs = require('fs'); + +const { + processDotSlashFileInPlace, + dangerouslyResignGeneratedFile, + validateAndParseDotSlashFile, +} = require('../dotslash-utils'); + +jest.useRealTimers(); + +let tmpDir: string; + +beforeEach(() => { + tmpDir = fs.mkdtempSync('dotslash-utils-test-'); +}); + +afterEach(() => { + fs.rmSync(tmpDir, {recursive: true}); +}); + +describe('processDotSlashFileInPlace', () => { + test('succeeds on a minimal valid DotSlash file', async () => { + const transformProviders = jest.fn(); + const contentsBefore = `#!/usr/bin/env dotslash +{ + "name": "test", + "platforms": {} +}`; + fs.writeFileSync(`${tmpDir}/entry-point`, contentsBefore); + await processDotSlashFileInPlace( + `${tmpDir}/entry-point`, + transformProviders, + ); + expect(transformProviders).not.toHaveBeenCalled(); + expect(fs.readFileSync(`${tmpDir}/entry-point`, 'utf8')).toBe( + contentsBefore, + ); + }); + + test('comments, multiple platforms, providers + replacement', async () => { + const transformProviders = jest.fn(); + const contentsBefore = `#!/usr/bin/env dotslash +// Top-level comment +{ + "name": "test", + "platforms": { + // Comment on linux-x86_64 + "linux-x86_64": { + "size": 0, + "hash": "sha256", + "digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "providers": [ + {"url": "https://primary.example.com/foo-linux.tar.gz", "weight": 3}, + {"url": "https://mirror1.example.com/foo-linux.tar.gz", "weight": 1}, + {"url": "https://mirror2.example.com/foo-linux.tar.gz", "weight": 1}, + {"url": "https://mirror3.example.com/foo-linux.tar.gz", "weight": 1} + ], + "format": "tar.gz", + "path": "bar" + }, + // Comment on macos-aarch64 + "macos-aarch64": { + "size": 0, + "hash": "sha256", + "digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "providers": [ + {"url": "https://primary.example.com/foo-mac.zip", "weight": 3}, + {"url": "https://mirror1.example.com/foo-mac.zip", "weight": 1}, + ], + "format": "zip", + "path": "bar", + } + } +}`; + fs.writeFileSync(`${tmpDir}/entry-point`, contentsBefore); + transformProviders.mockImplementationOnce( + (providers, suggestedFilename) => { + return [ + { + url: + 'https://example.com/replaced/' + + encodeURIComponent(suggestedFilename), + }, + ]; + }, + ); + transformProviders.mockImplementationOnce( + (providers, suggestedFilename) => { + return [ + ...providers, + { + url: + 'https://example.com/added/' + + encodeURIComponent(suggestedFilename), + }, + ]; + }, + ); + await processDotSlashFileInPlace( + `${tmpDir}/entry-point`, + transformProviders, + ); + expect(transformProviders.mock.calls).toMatchSnapshot( + 'transformProviders calls', + ); + expect(fs.readFileSync(`${tmpDir}/entry-point`, 'utf8')).toMatchSnapshot( + 'contents after processing', + ); + }); + + test('fails on an invalid DotSlash file (no shebang line)', async () => { + const transformProviders = jest.fn(); + const contentsBefore = `{ + "name": "test", + "platforms": {} +}`; + fs.writeFileSync(`${tmpDir}/entry-point`, contentsBefore); + await expect( + processDotSlashFileInPlace(`${tmpDir}/entry-point`, transformProviders), + ).rejects.toThrow(); + expect(transformProviders).not.toHaveBeenCalled(); + expect(fs.readFileSync(`${tmpDir}/entry-point`, 'utf8')).toBe( + contentsBefore, + ); + }); + + test('fails on an invalid DotSlash file (no platforms)', async () => { + const transformProviders = jest.fn(); + const contentsBefore = `#!/usr/bin/env dotslash +{ + "name": "test" +}`; + fs.writeFileSync(`${tmpDir}/entry-point`, contentsBefore); + await expect( + processDotSlashFileInPlace(`${tmpDir}/entry-point`, transformProviders), + ).rejects.toThrow(); + expect(transformProviders).not.toHaveBeenCalled(); + expect(fs.readFileSync(`${tmpDir}/entry-point`, 'utf8')).toBe( + contentsBefore, + ); + }); +}); + +describe('dangerouslyResignGeneratedFile', () => { + test('successfully re-signs a file', async () => { + const contentsBefore = `#!/usr/bin/env dotslash +// @${'generated SignedSource<<00000000000000000000000000000000' + '>>'} +{ + "name": "test", + "platforms": {} +}`; + fs.writeFileSync(`${tmpDir}/entry-point`, contentsBefore); + await dangerouslyResignGeneratedFile(`${tmpDir}/entry-point`); + expect(fs.readFileSync(`${tmpDir}/entry-point`, 'utf8')) + .toBe(`#!/usr/bin/env dotslash +// @${'generated SignedSource<<5ccb2839bdbd070dffcda52c6aa922a3' + '>>'} +{ + "name": "test", + "platforms": {} +}`); + }); +}); diff --git a/scripts/releases/utils/dotslash-utils.js b/scripts/releases/utils/dotslash-utils.js new file mode 100644 index 00000000000000..10609c2aa8403d --- /dev/null +++ b/scripts/releases/utils/dotslash-utils.js @@ -0,0 +1,134 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +const {promises: fs} = require('fs'); +const {parse, modify, applyEdits} = require('jsonc-parser'); +const signedsource = require('signedsource'); +const dotslash = require('@motizilberman/dotslash'); +const execFile = require('util').promisify(require('child_process').execFile); + +/*:: +type DotSlashProvider = { + type?: 'http', + url: string, +} | { + type: 'github-release', + repo: string, + tag: string, + name: string, +}; + +type JSONCFormattingOptions = { + tabSize?: number, + insertSpaces?: boolean, + eol?: string, +}; + +type DotSlashProvidersTransformFn = ( + providers: $ReadOnlyArray, + suggestedFilename: string, +) => ?$ReadOnlyArray; +*/ + +const DEFAULT_FORMATTING_OPTIONS /*: $ReadOnly */ = { + tabSize: 4, + insertSpaces: true, + eol: '\n', +}; + +function sanitizeFileNameComponent( + fileNameComponent /*: string */, +) /*: string */ { + return fileNameComponent.replace(/[^a-zA-Z0-9.]/g, '.'); +} + +function splitShebangFromContents( + contents /*: string */, +) /*: [?string, string] */ { + const shebangMatch = contents.match(/^#!.*\n/); + const shebang = shebangMatch ? shebangMatch[0] : null; + const contentsWithoutShebang = shebang + ? contents.substring(shebang.length) + : contents; + return [shebang, contentsWithoutShebang]; +} + +/** + * Process a DotSlash file and call a callback with the providers for each platform. + * The callback can return a new providers array to update the file. + * The function will preserve formatting and comments in the file (except any comments + * that are within the providers array). + */ +async function processDotSlashFileInPlace( + filename /*: string */, + transformProviders /*: DotSlashProvidersTransformFn */, + formattingOptions /*: $ReadOnly */ = DEFAULT_FORMATTING_OPTIONS, +) /*: Promise */ { + // Validate the file using `dotslash` itself so we can be reasonably sure that it conforms + // to the expected format. + await validateAndParseDotSlashFile(filename); + + const originalContents = await fs.readFile(filename, 'utf-8'); + const [shebang, originalContentsJson] = + splitShebangFromContents(originalContents); + const json = parse(originalContentsJson); + let intermediateContentsJson = originalContentsJson; + for (const [platform, platformSpec] of Object.entries(json.platforms)) { + const providers = platformSpec.providers; + const suggestedFilename = + `${sanitizeFileNameComponent(json.name)}-${platform}` + + (platformSpec.format ? `.${platformSpec.format}` : ''); + const newProviders = + transformProviders(providers, suggestedFilename) ?? providers; + if (newProviders !== providers) { + const edits = modify( + intermediateContentsJson, + ['platforms', platform, 'providers'], + newProviders, + { + formattingOptions, + }, + ); + intermediateContentsJson = applyEdits(intermediateContentsJson, edits); + } + } + if (originalContentsJson !== intermediateContentsJson) { + await fs.writeFile(filename, shebang + intermediateContentsJson); + // Validate the modified file to make sure we haven't broken it. + await validateAndParseDotSlashFile(filename); + } +} + +async function validateAndParseDotSlashFile(filename /*: string */) /*: any */ { + const {stdout} = await execFile(dotslash, ['--', 'parse', filename]); + return JSON.parse(stdout); +} + +async function dangerouslyResignGeneratedFile( + filename /*: string */, +) /*: Promise */ { + const GENERATED = '@' + 'generated'; + const PATTERN = new RegExp(`${GENERATED} (?:SignedSource<<([a-f0-9]{32})>>)`); + const originalContents = await fs.readFile(filename, 'utf-8'); + + const newContents = signedsource.signFile( + originalContents.replace(PATTERN, signedsource.getSigningToken()), + ); + await fs.writeFile(filename, newContents); +} + +module.exports = { + DEFAULT_FORMATTING_OPTIONS, + processDotSlashFileInPlace, + dangerouslyResignGeneratedFile, + validateAndParseDotSlashFile, +}; diff --git a/scripts/releases/write-dotslash-release-asset-urls.js b/scripts/releases/write-dotslash-release-asset-urls.js new file mode 100644 index 00000000000000..a0003e4377f130 --- /dev/null +++ b/scripts/releases/write-dotslash-release-asset-urls.js @@ -0,0 +1,110 @@ +/** + * 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 strict-local + * @format + */ + +'use strict'; + +const { + dangerouslyResignGeneratedFile, + processDotSlashFileInPlace, + validateAndParseDotSlashFile, +} = require('./utils/dotslash-utils'); +const {REPO_ROOT} = require('../shared/consts'); +const {parseArgs, styleText} = require('util'); +const path = require('path'); + +const FIRST_PARTY_DOTSLASH_FILES = [ + 'packages/debugger-shell/bin/react-native-devtools', +]; + +const config = { + allowPositionals: true, + options: { + help: {type: 'boolean'}, + }, +}; + +async function main() { + const { + positionals: [version], + values: {help}, + /* $FlowFixMe[incompatible-call] Natural Inference rollout. See + * https://fburl.com/workplace/6291gfvu */ + } = parseArgs(config); + + if (help) { + console.log(` + Usage: node ./scripts/releases/write-dotslash-release-asset-urls.js + + Inserts references to release assets URLs into first-party DotSlash files in + the repo, in preparation for publishing a new release and uploading the + assets (which happens in a separate step). +`); + return; + } + + if (version == null) { + throw new Error('Missing version argument'); + } + + await writeReleaseAssetUrlsToDotSlashFiles(version); +} + +async function writeReleaseAssetUrlsToDotSlashFiles( + version /*: string */, +) /*: Promise */ { + const releaseTag = `v${version}`; + for (const filename of FIRST_PARTY_DOTSLASH_FILES) { + const fullPath = path.join(REPO_ROOT, filename); + console.log(`Updating ${filename}...`); + await processDotSlashFileInPlace( + fullPath, + (providers, suggestedFilename) => { + providers = providers.filter(provider => { + // Remove any existing release asset URLs + if ( + (provider.type === 'http' || provider.type == null) && + provider.url.startsWith( + 'https://github.com/facebook/react-native/releases/download/', + ) + ) { + console.log(styleText('red', ` -${provider.url}`)); + return false; + } + console.log(styleText('dim', ` ${provider.url}`)); + return true; + }); + if (providers.length === 0) { + throw new Error( + 'No usable providers found for asset:', + suggestedFilename, + ); + } + const url = `https://github.com/facebook/react-native/releases/download/${encodeURIComponent(releaseTag)}/${encodeURIComponent(suggestedFilename)}`; + console.log(styleText('green', ` +${url}`)); + providers.unshift({ + url, + }); + console.log('\n'); + return providers; + }, + ); + await dangerouslyResignGeneratedFile(fullPath); + await validateAndParseDotSlashFile(fullPath); + } +} + +module.exports = { + FIRST_PARTY_DOTSLASH_FILES, + writeReleaseAssetUrlsToDotSlashFiles, +}; + +if (require.main === module) { + void main(); +} diff --git a/yarn.lock b/yarn.lock index 56412385c7ce2c..3aed06f5387963 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1203,7 +1203,20 @@ "@babel/parser" "^7.27.2" "@babel/types" "^7.27.1" -"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.8", "@babel/traverse@^7.26.9": +"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.9.tgz#4398f2394ba66d05d988b2ad13c219a2c857461a" + integrity sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.9" + "@babel/parser" "^7.26.9" + "@babel/template" "^7.26.9" + "@babel/types" "^7.26.9" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/traverse@^7.25.3", "@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.8", "@babel/traverse@^7.26.9": version "7.26.9" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.9.tgz#4398f2394ba66d05d988b2ad13c219a2c857461a" integrity sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg== @@ -1810,6 +1823,11 @@ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz#d4f6937353bc4568292654efb0a0e0532adbcba2" integrity sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw== +"@motizilberman/dotslash@0.5.7-1754587239403": + version "0.5.7-1754587239403" + resolved "https://registry.yarnpkg.com/@motizilberman/dotslash/-/dotslash-0.5.7-1754587239403.tgz#ad383b7861c246491f60ec069601fcdc5133c10f" + integrity sha512-8pHQbz1ebw3BuNnMsmsshdVLDhOMIsI1cSk8XnBA9iir8VTmuBnEwX19rQrC7P6jDWL0RNhOmEbdIrB14nX0OQ== + "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" @@ -1848,6 +1866,11 @@ resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-5.1.2.tgz#68a486714d7a7fd1df56cb9bc89a860a0de866de" integrity sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw== +"@octokit/auth-token@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-6.0.0.tgz#b02e9c08a2d8937df09a2a981f226ad219174c53" + integrity sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w== + "@octokit/core@^5.0.2": version "5.2.1" resolved "https://registry.yarnpkg.com/@octokit/core/-/core-5.2.1.tgz#58c21a5f689ee81e0b883b5aa77573a7ff1b4ea1" @@ -1874,6 +1897,19 @@ before-after-hook "^3.0.2" universal-user-agent "^7.0.0" +"@octokit/core@^7.0.2": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-7.0.3.tgz#0b5288995fed66920128d41cfeea34979d48a360" + integrity sha512-oNXsh2ywth5aowwIa7RKtawnkdH6LgU1ztfP9AIUCQCvzysB+WeU8o2kyyosDPwBZutPpjZDKPQGIzzrfTWweQ== + dependencies: + "@octokit/auth-token" "^6.0.0" + "@octokit/graphql" "^9.0.1" + "@octokit/request" "^10.0.2" + "@octokit/request-error" "^7.0.0" + "@octokit/types" "^14.0.0" + before-after-hook "^4.0.0" + universal-user-agent "^7.0.0" + "@octokit/endpoint@^10.1.4": version "10.1.4" resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-10.1.4.tgz#8783be38a32b95af8bcb6523af20ab4eed7a2adb" @@ -1882,6 +1918,14 @@ "@octokit/types" "^14.0.0" universal-user-agent "^7.0.2" +"@octokit/endpoint@^11.0.0": + version "11.0.0" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-11.0.0.tgz#189fcc022721b4c49d0307eea6be3de1cfb53026" + integrity sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ== + dependencies: + "@octokit/types" "^14.0.0" + universal-user-agent "^7.0.2" + "@octokit/endpoint@^9.0.6": version "9.0.6" resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.6.tgz#114d912108fe692d8b139cfe7fc0846dfd11b6c0" @@ -1908,6 +1952,15 @@ "@octokit/types" "^14.0.0" universal-user-agent "^7.0.0" +"@octokit/graphql@^9.0.1": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-9.0.1.tgz#eb258fc9981403d2d751720832652c385b6c1613" + integrity sha512-j1nQNU1ZxNFx2ZtKmL4sMrs4egy5h65OMDmSbVyuCzjOcwsHq6EaYjOTGXPQxgfiN8dJ4CriYHk6zF050WEULg== + dependencies: + "@octokit/request" "^10.0.2" + "@octokit/types" "^14.0.0" + universal-user-agent "^7.0.0" + "@octokit/openapi-types@^24.2.0": version "24.2.0" resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-24.2.0.tgz#3d55c32eac0d38da1a7083a9c3b0cca77924f7d3" @@ -1918,6 +1971,11 @@ resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-25.0.0.tgz#adeead36992abf966e89dcd53518d8b0dc910e0d" integrity sha512-FZvktFu7HfOIJf2BScLKIEYjDsw6RKc7rBJCdvCTfKsVnx2GEB/Nbzjr29DUdb7vQhlzS/j8qDzdditP0OC6aw== +"@octokit/openapi-types@^25.1.0": + version "25.1.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-25.1.0.tgz#5a72a9dfaaba72b5b7db375fd05e90ca90dc9682" + integrity sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA== + "@octokit/plugin-paginate-rest@11.4.4-cjs.2": version "11.4.4-cjs.2" resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.4-cjs.2.tgz#979a10d577bce7a393e8e65953887e42b0a05000" @@ -1932,6 +1990,13 @@ dependencies: "@octokit/types" "^13.10.0" +"@octokit/plugin-paginate-rest@^13.0.1": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.1.1.tgz#ca5bb1c7b85a583691263c1f788f607e9bcb74b3" + integrity sha512-q9iQGlZlxAVNRN2jDNskJW/Cafy7/XE52wjZ5TTvyhyOD904Cvx//DNyoO3J/MXJ0ve3rPoNWKEg5iZrisQSuw== + dependencies: + "@octokit/types" "^14.1.0" + "@octokit/plugin-request-log@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz#98a3ca96e0b107380664708111864cb96551f958" @@ -1942,6 +2007,11 @@ resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz#ccb75d9705de769b2aa82bcd105cc96eb0c00f69" integrity sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw== +"@octokit/plugin-request-log@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz#de1c1e557df6c08adb631bf78264fa741e01b317" + integrity sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q== + "@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1": version "13.3.2-cjs.1" resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.2-cjs.1.tgz#d0a142ff41d8f7892b6ccef45979049f51ecaa8d" @@ -1956,6 +2026,13 @@ dependencies: "@octokit/types" "^13.10.0" +"@octokit/plugin-rest-endpoint-methods@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-16.0.0.tgz#ba30ca387fc2ac8bd93cf9f951174736babebd97" + integrity sha512-kJVUQk6/dx/gRNLWUnAWKFs1kVPn5O5CYZyssyEoNYaFedqZxsfYs7DwI3d67hGz4qOwaJ1dpm07hOAD1BXx6g== + dependencies: + "@octokit/types" "^14.1.0" + "@octokit/request-error@^5.1.1": version "5.1.1" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.1.tgz#b9218f9c1166e68bb4d0c89b638edc62c9334805" @@ -1972,6 +2049,24 @@ dependencies: "@octokit/types" "^14.0.0" +"@octokit/request-error@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-7.0.0.tgz#48ae2cd79008315605d00e83664891a10a5ddb97" + integrity sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg== + dependencies: + "@octokit/types" "^14.0.0" + +"@octokit/request@^10.0.2": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-10.0.3.tgz#2ffdb88105ce20d25dcab8a592a7040ea48306c7" + integrity sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA== + dependencies: + "@octokit/endpoint" "^11.0.0" + "@octokit/request-error" "^7.0.0" + "@octokit/types" "^14.0.0" + fast-content-type-parse "^3.0.0" + universal-user-agent "^7.0.2" + "@octokit/request@^8.4.1": version "8.4.1" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.4.1.tgz#715a015ccf993087977ea4365c44791fc4572486" @@ -2013,6 +2108,16 @@ "@octokit/plugin-request-log" "^4.0.0" "@octokit/plugin-rest-endpoint-methods" "13.3.2-cjs.1" +"@octokit/rest@^22.0.0": + version "22.0.0" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-22.0.0.tgz#9026f47dacba9c605da3d43cce9432c4c532dc5a" + integrity sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA== + dependencies: + "@octokit/core" "^7.0.2" + "@octokit/plugin-paginate-rest" "^13.0.1" + "@octokit/plugin-request-log" "^6.0.0" + "@octokit/plugin-rest-endpoint-methods" "^16.0.0" + "@octokit/types@^13.0.0", "@octokit/types@^13.1.0", "@octokit/types@^13.10.0", "@octokit/types@^13.7.0", "@octokit/types@^13.8.0": version "13.10.0" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.10.0.tgz#3e7c6b19c0236c270656e4ea666148c2b51fd1a3" @@ -2027,6 +2132,13 @@ dependencies: "@octokit/openapi-types" "^25.0.0" +"@octokit/types@^14.1.0": + version "14.1.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-14.1.0.tgz#3bf9b3a3e3b5270964a57cc9d98592ed44f840f2" + integrity sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g== + dependencies: + "@octokit/openapi-types" "^25.1.0" + "@react-native-community/cli-clean@20.0.0-alpha.0": version "20.0.0-alpha.0" resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-20.0.0-alpha.0.tgz#befce1ea464acc1c3cf09503ccd421afd7bda059" @@ -3236,6 +3348,11 @@ before-after-hook@^3.0.2: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-3.0.2.tgz#d5665a5fa8b62294a5aa0a499f933f4a1016195d" integrity sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A== +before-after-hook@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-4.0.0.tgz#cf1447ab9160df6a40f3621da64d6ffc36050cb9" + integrity sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ== + bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -4710,6 +4827,11 @@ fast-content-type-parse@^2.0.0: resolved "https://registry.yarnpkg.com/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz#c236124534ee2cb427c8d8e5ba35a4856947847b" integrity sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q== +fast-content-type-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz#5590b6c807cc598be125e6740a9fde589d2b7afb" + integrity sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -6381,7 +6503,7 @@ jsonc-eslint-parser@^2.3.0: espree "^9.0.0" semver "^7.3.5" -jsonc-parser@3.3.1: +jsonc-parser@3.3.1, jsonc-parser@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.3.1.tgz#f2a524b4f7fd11e3d791e559977ad60b98b798b4" integrity sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==