Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions packages/cli/src/commands/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,29 +437,21 @@ async function createTemplateUri(
);

if (!useLegacyTemplate) {
// This will use ~ to grab the latest patch version.
//
// Because we allow for many PATCHes to occur for a version of react-native, it's not possible to know
// (without inspecting the template's npm metadata) which template works with which react-native version.
// We are guaranteed that the latest version of react-native will work with the latest version of the
// template on that version.
//
// Example:
//
// Suppose react-native 0.75.0 was released, and 0.74.8 was the previous version. If I ran
// `init --version 0.74.8` it would be guaranteed to work with the latest version of the template
// matching the MAJOR.MINOR, e.g. 0.74.21.
if (/nightly/.test(version)) {
logger.debug(
"[template]: you're using a nightly version of react-native",
);
// Template nightly versions and react-native@nightly versions don't match (template releases at a much
// lower cadence). The naming scheme we use for nightlies doesn't support '~'. We have to assume the user
// is running against the latest nightly:
// lower cadence). We have to assume the user is running against the latest nightly by pointing to the tag.
return `${TEMPLATE_PACKAGE_COMMUNITY}@nightly`;
}

return `${TEMPLATE_PACKAGE_COMMUNITY}@~${version}`;
// Special case to unblock a release. This will need to be cleaned up in the future once 0.75 RC2 is out.
if (version === '0.75.0-rc.1') {
return `${TEMPLATE_PACKAGE_COMMUNITY}@0.75.0-rc.1.1`;
}

return `${TEMPLATE_PACKAGE_COMMUNITY}@${version}`;
}

logger.debug(
Expand Down Expand Up @@ -497,12 +489,6 @@ async function createProject(
// 2. `--template` will always win over `--version` for the template.
//
// 3. For version < 0.75, the template ships with react-native.
if (semver.valid(version) == null) {
throw new Error(
`--version=${options.version} -> '${version}' isn't valid SEMVER`,
);
}

const templateUri = await createTemplateUri(options, version);

logger.debug(`Template: '${templateUri}'`);
Expand Down Expand Up @@ -549,15 +535,29 @@ export default (async function initialize(

validateProjectName(projectName);

const version = await npmResolveConcreteVersion(
options.platformName ?? 'react-native',
options.version ?? DEFAULT_VERSION,
);
let version = options.version ?? DEFAULT_VERSION;

try {
const updatedVersion = await npmResolveConcreteVersion(
options.platformName ?? 'react-native',
version,
);
logger.debug(`Mapped: ${version} -> ${updatedVersion}`);
version = updatedVersion;
} catch (e) {
logger.debug(
`Failed to get concrete version from '${version}': `,
e as any,
);
}

// From 0.75 it actually is useful to be able to specify both the template and react-native version.
// This should only be used by people who know what they're doing.
if (!!options.template && !!options.version) {
if (semver.gte(version, TEMPLATE_COMMUNITY_REACT_NATIVE_VERSION)) {
// 0.75.0-nightly-20240618-5df5ed1a8' -> 0.75.0
// 0.75.0-rc.1 -> 0.75.0
const semverVersion = semver.coerce(version)?.version ?? version;
if (semver.gte(semverVersion, TEMPLATE_COMMUNITY_REACT_NATIVE_VERSION)) {
logger.warn(
`Use ${chalk.bold('--template')} and ${chalk.bold(
'--version',
Expand Down
15 changes: 14 additions & 1 deletion packages/cli/src/tools/npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,20 @@ export async function npmResolveConcreteVersion(
): Promise<string> {
const url = new URL(registry);
url.pathname = `${packageName}/${tagOrVersion}`;
const json: any = await fetch(url).then((resp) => resp.json());
const resp = await fetch(url);
if (
[
200, // OK
301, // Moved Permanemently
302, // Found
304, // Not Modified
307, // Temporary Redirect
308, // Permanent Redirect
].indexOf(resp.status) === -1
) {
throw new Error(`Unknown version ${packageName}@${tagOrVersion}`);
}
const json: any = await resp.json();
return json.version;
}

Expand Down