(entries: string[], platform: 'ios' | 'android')
| 84 | } |
| 85 | |
| 86 | function resolveArchiveRootName(entries: string[], platform: 'ios' | 'android'): string { |
| 87 | const roots = new Set<string>(); |
| 88 | for (const entry of entries) { |
| 89 | const [root] = entry.split('/'); |
| 90 | if (root) roots.add(root); |
| 91 | } |
| 92 | const rootEntries = [...roots]; |
| 93 | if (platform === 'ios') { |
| 94 | const appRoots = rootEntries.filter((entry) => entry.toLowerCase().endsWith('.app')); |
| 95 | const appRoot = appRoots[0]; |
| 96 | if (appRoot !== undefined && appRoots.length === 1) return appRoot; |
| 97 | if (appRoots.length === 0) { |
| 98 | throw new AppError( |
| 99 | 'INVALID_ARGS', |
| 100 | 'iOS app bundle archives must contain a single top-level .app directory', |
| 101 | ); |
| 102 | } |
| 103 | throw new AppError( |
| 104 | 'INVALID_ARGS', |
| 105 | `iOS app bundle archives must contain exactly one top-level .app directory, found: ${appRoots.join(', ')}`, |
| 106 | ); |
| 107 | } |
| 108 | const rootEntry = rootEntries[0]; |
| 109 | if (rootEntry !== undefined && rootEntries.length === 1) return rootEntry; |
| 110 | throw new AppError( |
| 111 | 'INVALID_ARGS', |
| 112 | `Archive must contain a single top-level bundle, found: ${rootEntries.join(', ')}`, |
| 113 | ); |
| 114 | } |
| 115 | |
| 116 | function normalizeArchiveEntry(entry: string): string { |
| 117 | if (entry.includes('\0')) { |
no outgoing calls
no test coverage detected
searching dependent graphs…