const versionPattern = /^(\d+)\.(\d+)\.(\d+)(?:-beta\.(\d+))?$/; const stableIosBuildSlot = 999; function getNativeReleaseVersion(version) { const match = versionPattern.exec(version); if (!match) { throw new Error(`Cannot derive native release version from unsupported version: ${version}`); } const [, majorText, minorText, patchText, betaText] = match; const major = Number(majorText); const minor = Number(minorText); const patch = Number(patchText); const betaNumber = betaText === undefined ? null : Number(betaText); if (minor > 999 || patch > 999) { throw new Error(`Cannot derive collision-free native version from: ${version}`); } if (betaNumber !== null && (betaNumber < 1 || betaNumber >= stableIosBuildSlot)) { throw new Error(`iOS beta number must be between 1 and 998: ${version}`); } const versionCode = major * 1_000_000 + minor * 1_000 + patch; if (!Number.isSafeInteger(versionCode) || versionCode <= 0 || versionCode > 2_100_000_000) { throw new Error(`Derived Android versionCode is out of range: ${versionCode}`); } const iosBuildSlot = betaNumber ?? stableIosBuildSlot; const iosBuildNumber = versionCode * 1_000 + iosBuildSlot; if (!Number.isSafeInteger(iosBuildNumber)) { throw new Error(`Derived iOS buildNumber is out of range: ${iosBuildNumber}`); } return { appVersion: `${major}.${minor}.${patch}`, androidVersionCode: versionCode, iosBuildNumber: String(iosBuildNumber), }; } module.exports = { getNativeReleaseVersion };