33import { readFile , writeFile } from 'node:fs/promises'
44
55import fg from 'fast-glob'
6- import { valid , satisfies } from 'semver'
6+ import { valid , satisfies , gte } from 'semver'
77
88const FUTURE_NEXT_PATCH_VERSION = '14.999.0'
99
10+ const NEXT_VERSION_REQUIRES_REACT_19 = '14.3.0-canary.45'
11+ // TODO: Update this when React 19 is released
12+ const REACT_19_VERSION = '19.0.0-rc-3f1436cca1-20240516'
13+ const REACT_18_VERSION = '18.2.0'
14+
1015/**
1116 * Check if current next version satisfies a semver constraint
1217 * @param {string } condition Semver constraint
@@ -20,6 +25,17 @@ export function nextVersionSatisfies(condition) {
2025 return satisfies ( checkVersion , condition ) || version === condition
2126}
2227
28+ /**
29+ * Check if current next version requires React 19
30+ * @param {string } version Next version
31+ * @returns {boolean } True if current next version requires React 19
32+ */
33+
34+ export function nextVersionRequiresReact19 ( version ) {
35+ // @ts -expect-error Mistake in semver types
36+ return gte ( version , NEXT_VERSION_REQUIRES_REACT_19 , { includePrerelease : true } )
37+ }
38+
2339/**
2440 * Finds all package.json in fixture directory and updates 'next' version to a given version
2541 * If there is test.dependencies.next, it will only update if the version satisfies the constraint in that field
@@ -29,12 +45,13 @@ export function nextVersionSatisfies(condition) {
2945 * @param {string } [options.logPrefix] Text to prefix logs with
3046 * @param {'update' | 'revert' } [options.operation] This just informs log output wording, otherwise it has no effect
3147 * @param {boolean } [options.silent] Doesn't produce any logs if truthy
48+ * @param {boolean } [options.updateReact] Update React version to match Next version
3249 * @returns {Promise<void> }
3350 */
3451export async function setNextVersionInFixture (
3552 cwd ,
3653 version ,
37- { logPrefix = '' , operation = 'update' , silent = false } = { } ,
54+ { logPrefix = '' , operation = 'update' , silent = false , updateReact = true } = { } ,
3855) {
3956 // use NEXT_RESOLVED_VERSION env var if exists and if passed version matches version from NEXT_VERSION
4057 // otherwise use whatever is passed
@@ -65,7 +82,7 @@ export async function setNextVersionInFixture(
6582 if ( packageJson . dependencies ?. next ) {
6683 const versionConstraint = packageJson . test ?. dependencies ?. next
6784 // We can't use semver to check "canary" or "latest", so we use a fake future minor version
68- const checkVersion = isSemverVersion ? version : FUTURE_NEXT_PATCH_VERSION
85+ const checkVersion = isSemverVersion ? resolvedVersion : FUTURE_NEXT_PATCH_VERSION
6986 if (
7087 operation === 'update' &&
7188 versionConstraint &&
@@ -80,6 +97,12 @@ export async function setNextVersionInFixture(
8097 return
8198 }
8299 packageJson . dependencies . next = version
100+ if ( updateReact && nextVersionRequiresReact19 ( checkVersion ) ) {
101+ const reactVersion = operation === 'update' ? REACT_19_VERSION : REACT_18_VERSION
102+ packageJson . dependencies . react = reactVersion
103+ packageJson . dependencies [ 'react-dom' ] = reactVersion
104+ }
105+
83106 await writeFile ( packageJsonPath , JSON . stringify ( packageJson , null , 2 ) + '\n' )
84107 }
85108 } ) ,
0 commit comments