#!/usr/bin/env swift import Foundation // Copy the URLTemplateProcessor code for testing struct URLTemplateProcessor { static func processTemplate(_ template: String, with parameters: [String: String]) -> String { var processedURL = template let extractedParams = extractParameters(from: template) for param in extractedParams { let placeholder = "{\(param.name)" + (param.defaultValue != nil ? ",default=\(param.defaultValue!)" : "") + "}" let value = parameters[param.name] ?? param.defaultValue ?? "" processedURL = processedURL.replacingOccurrences(of: placeholder, with: value) } return processedURL } static func extractParameters(from template: String) -> [TemplateParameter] { var parameters: [TemplateParameter] = [] // Updated pattern to handle optional spaces around comma and default= let pattern = "\\{([^,}]+)(?:\\s*,\\s*default\\s*=\\s*([^}]+))?\\}" guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return parameters } let matches = regex.matches(in: template, options: [], range: NSRange(location: 0, length: template.utf16.count)) for match in matches { let nameRange = match.range(at: 1) let defaultRange = match.range(at: 2) if let nameSwiftRange = Range(nameRange, in: template) { let name = String(template[nameSwiftRange]).trimmingCharacters(in: .whitespaces) var defaultValue: String? = nil if defaultRange.location != NSNotFound, let defaultSwiftRange = Range(defaultRange, in: template) { defaultValue = String(template[defaultSwiftRange]).trimmingCharacters(in: .whitespaces) } parameters.append(TemplateParameter(name: name, defaultValue: defaultValue)) } } return parameters } static func validateTemplate(_ template: String) -> Bool { let extractedParams = extractParameters(from: template) // Check if all placeholders are valid let pattern = "\\{[^{}]*\\}" guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return false } let matches = regex.matches(in: template, options: [], range: NSRange(location: 0, length: template.utf16.count)) // Each match should correspond to a valid parameter for match in matches { if let matchRange = Range(match.range, in: template) { let matchString = String(template[matchRange]) let isValid = extractedParams.contains { param in matchString.contains(param.name) } if !isValid { return false } } } return true } static func hasParameters(_ template: String) -> Bool { return template.contains("{") && template.contains("}") } } struct TemplateParameter { let name: String let defaultValue: String? var isRequired: Bool { return defaultValue == nil } } // Test cases print("Testing URLTemplateProcessor...") let testCases = [ "https://google.com/search?q={query, default=hello}", "https://google.com/search?q={query}", "https://github.com/{user}/{repo}", "https://youtube.com/watch?v={videoId}", "https://maps.apple.com/?q={location,default=New York}", "https://example.com/{invalid syntax}", "https://example.com/no-parameters", "https://example.com/{query,default=test}/{page,default=1}" ] for testCase in testCases { let isValid = URLTemplateProcessor.validateTemplate(testCase) let hasParams = URLTemplateProcessor.hasParameters(testCase) let parameters = URLTemplateProcessor.extractParameters(from: testCase) print("\nTest: \(testCase)") print(" Valid: \(isValid)") print(" Has Parameters: \(hasParams)") print(" Parameters: \(parameters.map { "\($0.name)" + (($0.defaultValue != nil) ? ",default=\($0.defaultValue!)" : "") })") if isValid && hasParams { print(" ✅ Would show blue border") } else if !hasParams { print(" ⚠️ Would show warning (no parameters)") } else { print(" ❌ Would show error (invalid)") } }