jgsamudio
7/12/2018 - 2:26 AM

A simple CSS to Swift Model Parser.

A simple CSS to Swift Model Parser.

extension String {
 
    /// Returns the substring that contains the characters after first occurrence of the provided token.
    ///
    /// - Parameter token: The token
    /// - Returns: The substring that contains the characters after first occurrence of the provided token.
    func removeLeading(startWith token: String) -> String {
        if let token = range(of: token) {
            var newString = self
            newString.removeSubrange(startIndex..<token.upperBound)
            return newString
        }
        return self
    }
    
    /// Returns the substring that contains the characters before first occurrence of the provided token.
    ///
    /// - Parameter token: The token
    /// - Returns: The substring that contains the characters before first occurrence of the provided token.
    func removeTrailing(startWith token: String) -> String {
        if let token = range(of: token) {
            var newString = self
            newString.removeSubrange(token.lowerBound..<endIndex)
            return newString
        }
        return self
    }
    
    /// Replaces the occurrences of the strings provided.
    ///
    /// - Parameter strings: Strings to remove.
    /// - Returns: Updated string with the strings removed.
    func replacingOccurrences(strings: [String]) -> String {
        var updatedString = self
        for string in strings {
            updatedString = updatedString.replacingOccurrences(of: string, with: "")
        }
        return updatedString
    }
 
}
struct CssStyle {
    
    /// Name of the style.
    let name: String
    
    /// Properties of the style.
    let properties: [String: String]
    
}
final class CssParser {
    
    /// Parses the CSS file string into an array of CSS styles.
    ///
    /// - Parameter fileContent: CSS file content.
    /// - Returns: Array of CSS styles.
    static func parse(fileContent: String) -> [CssStyle] {
        var styles = [CssStyle]()
        var pendingStyleName = ""
        var pendingStyleProperties = [String: String]()
        var pendingLine = ""
        
        for character in fileContent {
            pendingLine.append(character)
            
            if character == "{" {
                pendingStyleName = pendingLine.replacingOccurrences(strings: [" ", "\n", "{"])
                pendingLine = ""
            } else if character == ";" {
                let propertyLine = pendingLine.replacingOccurrences(strings: [";", "\n"])
                let key = propertyLine.removeTrailing(startWith: ":").replacingOccurrences(strings: [" "])
                let value = propertyLine.removeLeading(startWith: ":").removeLeading(startWith: " ")
                pendingStyleProperties[key] = value
                pendingLine = ""
            } else if character == "}" {
                styles.append(CssStyle(name: pendingStyleName, properties: pendingStyleProperties))
                pendingStyleProperties.removeAll()
                pendingStyleName = ""
                pendingLine = ""
            }
        }
        return styles
    }
    
}