import Foundation /// Where a produced file goes, and what it is called. enum OutputNaming { /// ``name.pdf`` for ``photo.jpg`` — appends ``-2``, ``-3`` … when the /// target already exists (unless the user asked to overwrite). static func destination(for source: URL, format: Format, settings: Settings = .shared) -> URL { let base = source.deletingPathExtension().lastPathComponent let directory: URL switch settings.outputLocation { case .besideOriginal: directory = source.deletingLastPathComponent() case .chosenFolder: let folder = settings.resolvedOutputFolder directory = FileManager.default.fileExists(atPath: folder.path) ? folder : source.deletingLastPathComponent() } let candidate = directory.appendingPathComponent(base).appendingPathExtension(format.ext) return settings.conflictPolicy == .overwrite ? candidate : availableURL(for: candidate) } /// A sibling of any output a tool produces (e.g. ``photo-compressed.jpg``). static func sibling(for source: URL, suffix: String, extension ext: String? = nil) -> URL { let base = source.deletingPathExtension().lastPathComponent let directory = source.deletingLastPathComponent() let resolvedExtension = ext ?? source.pathExtension return availableURL( for: directory.appendingPathComponent(base + suffix).appendingPathExtension(resolvedExtension) ) } /// A working directory for multi-file outputs (split pages, extracted /// images, unarchived trees). static func artifactDirectory(for source: URL, suffix: String) -> URL { let base = source.deletingPathExtension().lastPathComponent let directory = source.deletingLastPathComponent() let url = directory.appendingPathComponent(base + suffix, isDirectory: true) var candidate = url var index = 2 while FileManager.default.fileExists(atPath: candidate.path) { candidate = directory.appendingPathComponent("\(base + suffix) \(index)", isDirectory: true) index += 1 } return candidate } /// ``foo 2.txt``, ``foo 3.txt`` … until the name is free. static func availableURL(for url: URL) -> URL { guard FileManager.default.fileExists(atPath: url.path) else { return url } let directory = url.deletingLastPathComponent() let ext = url.pathExtension let base = url.deletingPathExtension().lastPathComponent var index = 2 while true { let name = ext.isEmpty ? "\(base) \(index)" : "\(base) \(index).\(ext)" let candidate = directory.appendingPathComponent(name) if !FileManager.default.fileExists(atPath: candidate.path) { return candidate } index += 1 } } static func uniqueChild(of directory: URL, suggestedName: String) -> URL { availableURL(for: directory.appendingPathComponent(suggestedName)) } }