import * as path from 'path'; import * as fs from 'fs'; import * as smolToml from 'smol-toml'; import { FsHelpers } from '../mod_fs/index.js'; export interface ICargoWorkspaceInfo { isWorkspace: boolean; rustDir: string; binTargets: string[]; } export class CargoConfig { private rustDir: string; constructor(rustDir: string) { this.rustDir = rustDir; } public async parse(): Promise { const cargoTomlPath = path.join(this.rustDir, 'Cargo.toml'); const content = await fs.promises.readFile(cargoTomlPath, 'utf-8'); const parsed = smolToml.parse(content); const isWorkspace = !!(parsed as any).workspace; let binTargets: string[] = []; if (isWorkspace) { binTargets = await this.collectWorkspaceBinTargets(parsed); } else { binTargets = this.collectCrateBinTargets(parsed, this.rustDir); } return { isWorkspace, rustDir: this.rustDir, binTargets, }; } private async collectWorkspaceBinTargets(parsed: any): Promise { const members: string[] = parsed.workspace?.members || []; const binTargets: string[] = []; for (const member of members) { const memberDir = path.join(this.rustDir, member); const memberCargoToml = path.join(memberDir, 'Cargo.toml'); if (!(await FsHelpers.fileExists(memberCargoToml))) { continue; } const memberContent = await fs.promises.readFile(memberCargoToml, 'utf-8'); const memberParsed = smolToml.parse(memberContent); const memberBins = this.collectCrateBinTargets(memberParsed, memberDir); binTargets.push(...memberBins); } return binTargets; } private collectCrateBinTargets(parsed: any, crateDir: string): string[] { const binTargets: string[] = []; // Check for explicit [[bin]] entries if (Array.isArray(parsed.bin)) { for (const bin of parsed.bin) { if (bin.name) { binTargets.push(bin.name); } } } // If no [[bin]] but package has a name and src/main.rs exists, use package name if (binTargets.length === 0 && parsed.package?.name) { const mainRsPath = path.join(crateDir, 'src', 'main.rs'); // Use sync check since this is called during parsing try { const stat = fs.statSync(mainRsPath); if (stat.isFile()) { binTargets.push(parsed.package.name); } } catch { // No main.rs, not a binary crate } } return binTargets; } }