class MaterialSyncExportPath class << self def build prefix: nil, relative_path: nil, filename: nil, source_file_id: nil path = normalize_path(relative_path) path = fallback_filename(filename, source_file_id) if path.blank? normalized_prefix = normalize_path(prefix) return path if normalized_prefix.blank? return normalized_prefix if path.blank? [normalized_prefix, path].join('/') end def normalize_path path raw = path.to_s.delete("\0").tr('\\', '/').strip raw = raw.sub(%r{\A[A-Za-z]:/+}, '') raw = raw.sub(%r{\A/+}, '') return nil if raw.blank? segments = raw.split('/').filter_map do |segment| normalized = normalize_segment(segment) normalized.presence end return nil if segments.empty? segments.join('/') end def uniquify path, source_file_id normalized = normalize_path(path) return normalized if normalized.blank? || source_file_id.blank? ext = File.extname(normalized) base = ext.present? ? normalized.delete_suffix(ext) : normalized "#{ base }--#{ source_file_id }#{ ext }" end private def fallback_filename filename, source_file_id name = normalize_path(filename) return name if name.present? return nil if source_file_id.blank? source_file_id.to_s end def normalize_segment segment cleaned = segment.to_s.delete("\0").tr('\\/', '_').strip return nil if cleaned.blank? || cleaned == '.' return '__' if cleaned == '..' cleaned end end end