import { logger } from '../../../logger/index.ts'; import { getSiblingFileName, localPathExists } from '../../../util/fs/index.ts'; import { newlineRegex, regEx } from '../../../util/regex.ts'; import { coerceString } from '../../../util/string.ts'; import { GitTagsDatasource } from '../../datasource/git-tags/index.ts'; import { GithubTagsDatasource } from '../../datasource/github-tags/index.ts'; import { GitlabTagsDatasource } from '../../datasource/gitlab-tags/index.ts'; import { PodDatasource } from '../../datasource/pod/index.ts'; import type { PackageDependency, PackageFileContent } from '../types.ts'; import type { ParsedLine } from './types.ts'; const regexMappings = [ regEx(`^\\s*pod\\s+(['"])(?[^'"/]+)(/(?[^'"]+))?(['"])`), regEx( `^\\s*pod\\s+(['"])[^'"]+(['"])\\s*,\\s*(['"])(?[^'"]+)(['"])\\s*$`, ), regEx(`,\\s*:git\\s*=>\\s*(['"])(?[^'"]+)(['"])`), regEx(`,\\s*:tag\\s*=>\\s*(['"])(?[^'"]+)(['"])`), regEx(`,\\s*:path\\s*=>\\s*(['"])(?[^'"]+)(['"])`), regEx(`^\\s*source\\s*(['"])(?[^'"]+)(['"])`), ]; export function parseLine(line: string): ParsedLine { let result: ParsedLine = {}; if (!line) { return result; } for (const regex of Object.values(regexMappings)) { const match = regex.exec(line.replace(regEx(/#.*$/), '')); if (match?.groups) { result = { ...result, ...match.groups }; } } if (result.spec) { const depName = result.subspec ? `${result.spec}/${result.subspec}` : result.spec; const specName = result.spec; if (depName) { result.depName = depName; } if (specName) { result.specName = specName; } delete result.spec; delete result.subspec; } return result; } export function gitDep(parsedLine: ParsedLine): PackageDependency | null { const { depName, git, tag } = parsedLine; const platformMatch = regEx( /[@/](?github|gitlab)\.com[:/](?[^/]+)\/(?[^/]+)/, ).exec(coerceString(git)); if (platformMatch?.groups) { const { account, repo, platform } = platformMatch.groups; if (account && repo) { const datasource = platform === 'github' ? GithubTagsDatasource.id : GitlabTagsDatasource.id; return { datasource, depName, packageName: `${account}/${repo.replace(regEx(/\.git$/), '')}`, currentValue: tag, }; } } return { datasource: GitTagsDatasource.id, depName, packageName: git, currentValue: tag, }; } export async function extractPackageFile( content: string, packageFile: string, ): Promise { logger.trace(`cocoapods.extractPackageFile(${packageFile})`); const deps: PackageDependency[] = []; const lines: string[] = content.split(newlineRegex); const registryUrls: string[] = []; for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) { const line = lines[lineNumber]; const parsedLine = parseLine(line); const { depName, specName, currentValue, git, tag, path, source, }: ParsedLine = parsedLine; if (source) { registryUrls.push(source.replace(regEx(/\/*$/), '')); } if (depName) { const managerData = { lineNumber }; let dep: PackageDependency = { depName, sharedVariableName: specName, skipReason: 'unspecified-version', }; if (currentValue) { dep = { depName, sharedVariableName: specName, datasource: PodDatasource.id, currentValue, managerData, registryUrls, }; } else if (git) { if (tag) { dep = { ...gitDep(parsedLine), managerData }; } else { dep = { depName, sharedVariableName: specName, skipReason: 'git-dependency', }; } } else if (path) { dep = { depName, sharedVariableName: specName, skipReason: 'path-dependency', }; } deps.push(dep); } } const res: PackageFileContent = { deps }; const lockFile = getSiblingFileName(packageFile, 'Podfile.lock'); // istanbul ignore if if (await localPathExists(lockFile)) { res.lockFiles = [lockFile]; } return res; }