61 lines
3.8 KiB
TypeScript
61 lines
3.8 KiB
TypeScript
// App Store platforms of one app record. An app can have an iOS and a macOS (tvOS, visionOS) version at the same time,
|
|
// each with its own state and its own review submission (pitfall 79): every version lookup filters by platform, and a
|
|
// command that needs one version picks the platform that has it, or asks for --platform when several do.
|
|
import type { Asc, J } from './asc';
|
|
|
|
export type AscPlatform = 'IOS' | 'MAC_OS' | 'TV_OS' | 'VISION_OS';
|
|
export const ASC_PLATFORMS: AscPlatform[] = ['IOS', 'MAC_OS', 'TV_OS', 'VISION_OS'];
|
|
const FLAG: Record<string, AscPlatform> = { ios: 'IOS', macos: 'MAC_OS', tvos: 'TV_OS', visionos: 'VISION_OS' };
|
|
const LABEL: Record<AscPlatform, string> = { IOS: 'iOS', MAC_OS: 'macOS', TV_OS: 'tvOS', VISION_OS: 'visionOS' };
|
|
/** The console's URL segment of a platform's version page. */
|
|
export const CONSOLE_SEGMENT: Record<AscPlatform, string> = { IOS: 'ios', MAC_OS: 'macos', TV_OS: 'appletvos', VISION_OS: 'visionos' };
|
|
|
|
/** --platform ios|macos|tvos|visionos (also the API names IOS, MAC_OS, ...) -> the API's platform; undefined when not
|
|
* given; throws on anything else. Pure. */
|
|
export function parsePlatform(v: string | undefined): AscPlatform | undefined {
|
|
if (v == null || v === '') return undefined;
|
|
const k = v.toLowerCase().replace(/[_\s-]/g, '');
|
|
const p = FLAG[k] ?? FLAG[k.replace(/^appletv/, 'tv')];
|
|
if (!p) throw new Error(`--platform: ios | macos | tvos | visionos (got "${v}")`);
|
|
return p;
|
|
}
|
|
|
|
/** "iOS", "macOS", ... for any platform string (unknown ones as they are). Pure. */
|
|
export const platformLabel = (p: string | undefined | null): string => LABEL[(p ?? 'IOS') as AscPlatform] ?? String(p);
|
|
|
|
export const platformOf = (v: J): AscPlatform => (v?.attributes?.platform ?? 'IOS') as AscPlatform;
|
|
export const stateOf = (v: J): string => v?.attributes?.appVersionState ?? v?.attributes?.appStoreState ?? '';
|
|
/** "0.8.7 (macOS)": a version as people read it. */
|
|
export const versionLabel = (v: J): string => `${v?.attributes?.versionString ?? '?'} (${platformLabel(platformOf(v))})`;
|
|
|
|
/** The appStoreVersions list path of one platform. */
|
|
export const versionsPath = (appId: string, platform: AscPlatform, limit = 50): string =>
|
|
`/v1/apps/${appId}/appStoreVersions?filter[platform]=${platform}&limit=${limit}`;
|
|
|
|
/**
|
|
* The platform a command works on. `flag` (--platform) wins. Else the platforms that have a version `needs` accepts:
|
|
* one -> that one; several -> an error naming them all (ask for --platform); none -> the only platform the app has
|
|
* versions on, else iOS. Pure.
|
|
*/
|
|
export function pickPlatform(versions: J[], needs: ((v: J) => boolean) | ((v: J) => boolean)[], flag: AscPlatform | undefined, what: string): AscPlatform {
|
|
if (flag) return flag;
|
|
// several tests: the first one any version passes decides (e.g. "this version string, editable", then "editable")
|
|
if (Array.isArray(needs)) {
|
|
for (const n of needs) if (versions.some(n)) return pickPlatform(versions, n, undefined, what);
|
|
return pickPlatform(versions, () => false, undefined, what);
|
|
}
|
|
const hits = [...new Set(versions.filter(needs).map(platformOf))];
|
|
if (hits.length === 1) return hits[0]!;
|
|
if (hits.length > 1) {
|
|
const which = versions.filter(needs).map(v => `${versionLabel(v)} ${stateOf(v)}`).join(', ');
|
|
throw new Error(`${what} on more than one platform (${which}): run it again with --platform ${hits.map(p => Object.keys(FLAG).find(k => FLAG[k] === p)).join(' or --platform ')}`);
|
|
}
|
|
const all = [...new Set(versions.map(platformOf))];
|
|
return all.length === 1 ? all[0]! : 'IOS';
|
|
}
|
|
|
|
/** Every App Store version of the app on every platform (only to pick the platform; the command then reads its
|
|
* platform's list with filter[platform]). */
|
|
export async function allVersions(c: Asc, appId: string): Promise<J[]> {
|
|
return c.all(`/v1/apps/${appId}/appStoreVersions?filter[platform]=${ASC_PLATFORMS.join(',')}&limit=200`);
|
|
}
|