/* eslint-disable no-undef */ export const getProjectTypeForUrl = (type, categories) => { return getProjectTypeForUrlShorthand(type, categories); }; export const getProjectTypeForUrlShorthand = (type, categories, overrideTags) => { const tags = overrideTags ?? useTags().value; if (type === "mod") { const isMod = categories.some((category) => { return tags.loaderData.modLoaders.includes(category); }); const isPlugin = categories.some((category) => { return tags.loaderData.allPluginLoaders.includes(category); }); const isDataPack = categories.some((category) => { return tags.loaderData.dataPackLoaders.includes(category); }); if (isDataPack) { return "datapack"; } else if (isPlugin) { return "plugin"; } else if (isMod) { return "mod"; } else { return "mod"; } } else { return type; } }; export const getProjectLink = (project) => { return `/${getProjectTypeForUrl(project.project_type, project.loaders)}/${ project.slug ? project.slug : project.id }`; }; export const getVersionLink = (project, version) => { if (version) { return getProjectLink(project) + "/version/" + version.id; } else { return getProjectLink(project); } }; export const isApproved = (project) => { return project && APPROVED_PROJECT_STATUSES.includes(project.status); }; export const isListed = (project) => { return project && LISTED_PROJECT_STATUSES.includes(project.status); }; export const isUnlisted = (project) => { return project && UNLISTED_PROJECT_STATUSES.includes(project.status); }; export const isPrivate = (project) => { return project && PRIVATE_PROJECT_STATUSES.includes(project.status); }; export const isRejected = (project) => { return project && REJECTED_PROJECT_STATUSES.includes(project.status); }; export const isUnderReview = (project) => { return project && UNDER_REVIEW_PROJECT_STATUSES.includes(project.status); }; export const isDraft = (project) => { return project && DRAFT_PROJECT_STATUSES.includes(project.status); }; export const APPROVED_PROJECT_STATUSES = ["approved", "archived", "unlisted", "private"]; export const LISTED_PROJECT_STATUSES = ["approved", "archived"]; export const UNLISTED_PROJECT_STATUSES = ["unlisted", "withheld"]; export const PRIVATE_PROJECT_STATUSES = ["private", "rejected", "processing"]; export const REJECTED_PROJECT_STATUSES = ["rejected", "withheld"]; export const UNDER_REVIEW_PROJECT_STATUSES = ["processing"]; export const DRAFT_PROJECT_STATUSES = ["draft"]; export function getVersionsToDisplay(project, overrideTags) { const tags = overrideTags ?? useTags().value; const projectVersions = project.game_versions.slice(); const allVersions = tags.gameVersions.slice(); const allSnapshots = allVersions.filter((version) => version.version_type === "snapshot"); const allReleases = allVersions.filter((version) => version.version_type === "release"); const allLegacy = allVersions.filter( (version) => version.version_type !== "snapshot" && version.version_type !== "release", ); { const indices = allVersions.reduce((map, gameVersion, index) => { map[gameVersion.version] = index; return map; }, {}); projectVersions.sort((a, b) => indices[a] - indices[b]); } const releaseVersions = projectVersions.filter((projVer) => allReleases.some((gameVer) => gameVer.version === projVer), ); const latestReleaseVersionDate = Date.parse( allReleases.find((version) => version.version === releaseVersions[0])?.date, ); const latestSnapshot = projectVersions.find((projVer) => allSnapshots.some( (gameVer) => gameVer.version === projVer && (!latestReleaseVersionDate || latestReleaseVersionDate < Date.parse(gameVer.date)), ), ); const allReleasesGrouped = groupVersions( allReleases.map((release) => release.version), false, ); const projectVersionsGrouped = groupVersions(releaseVersions, true); const releaseVersionsAsRanges = projectVersionsGrouped.map(({ major, minor }) => { if (minor.length === 1) { return formatVersion(major, minor[0]); } if ( allReleasesGrouped .find((x) => x.major === major) .minor.every((value, index) => value === minor[index]) ) { return `${major}.x`; } return `${formatVersion(major, minor[0])}–${formatVersion(major, minor[minor.length - 1])}`; }); const legacyVersionsAsRanges = groupConsecutiveIndices( projectVersions.filter((projVer) => allLegacy.some((gameVer) => gameVer.version === projVer)), allLegacy, ); let output = [...legacyVersionsAsRanges]; // show all snapshots if there's no release versions if (releaseVersionsAsRanges.length === 0) { const snapshotVersionsAsRanges = groupConsecutiveIndices( projectVersions.filter((projVer) => allSnapshots.some((gameVer) => gameVer.version === projVer), ), allSnapshots, ); output = [...snapshotVersionsAsRanges, ...output]; } else { output = [...releaseVersionsAsRanges, ...output]; } if (latestSnapshot) { output = [latestSnapshot, ...output]; } return output; } const mcVersionRegex = /^([0-9]+.[0-9]+)(.[0-9]+)?$/; function groupVersions(versions, consecutive = false) { return versions .slice() .reverse() .reduce((ranges, version) => { const matchesVersion = version.match(mcVersionRegex); if (matchesVersion) { const majorVersion = matchesVersion[1]; const minorVersion = matchesVersion[2]; const minorNumeric = minorVersion ? parseInt(minorVersion.replace(".", "")) : 0; let prevInRange; if ( (prevInRange = ranges.find( (x) => x.major === majorVersion && (!consecutive || x.minor.at(-1) === minorNumeric - 1), )) ) { prevInRange.minor.push(minorNumeric); return ranges; } return [...ranges, { major: majorVersion, minor: [minorNumeric] }]; } return ranges; }, []) .reverse(); } function groupConsecutiveIndices(versions, referenceList) { if (!versions || versions.length === 0) { return []; } const referenceMap = new Map(); referenceList.forEach((item, index) => { referenceMap.set(item.version, index); }); const sortedList = versions.slice().sort((a, b) => referenceMap.get(a) - referenceMap.get(b)); const ranges = []; let start = sortedList[0]; let previous = sortedList[0]; for (let i = 1; i < sortedList.length; i++) { const current = sortedList[i]; if (referenceMap.get(current) !== referenceMap.get(previous) + 1) { ranges.push(validateRange(`${previous}–${start}`)); start = current; } previous = current; } ranges.push(validateRange(`${previous}–${start}`)); return ranges; } function validateRange(range) { switch (range) { case "rd-132211–b1.8.1": return "All legacy versions"; case "a1.0.4–b1.8.1": return "All alpha and beta versions"; case "a1.0.4–a1.2.6": return "All alpha versions"; case "b1.0–b1.8.1": return "All beta versions"; case "rd-132211–inf20100618": return "All pre-alpha versions"; } const splitRange = range.split("–"); if (splitRange && splitRange[0] === splitRange[1]) { return splitRange[0]; } return range; } function formatVersion(major, minor) { return minor === 0 ? major : `${major}.${minor}`; }