diff --git a/Package.swift b/Package.swift
index 365be613..2350e9d4 100644
--- a/Package.swift
+++ b/Package.swift
@@ -26,13 +26,43 @@ let package = Package(
                 .product(name: "Collections", package: "swift-collections")
             ]
         ),
+        .target(
+            name: "Converter",
+            dependencies: [
+                .target(name: "HTMLKit")
+            ]
+        ),
         .testTarget(
             name: "HTMLKitTests",
-            dependencies: ["HTMLKit"],
+            dependencies: [
+                .target(name: "HTMLKit")
+            ],
+            resources: [
+                .process("Localization")
+            ]
+        ),
+        .testTarget(
+            name: "ConverterTests",
+            dependencies: [
+                .target(name: "Converter")
+            ],
             resources: [
-                .process("Localization"),
                 .process("Conversion")
             ]
+        ),
+        .executableTarget(
+            name: "ConvertCommand",
+            dependencies: [
+                .target(name: "Converter")
+            ],
+            path: "Sources/Commands"
+        ),
+        .plugin(
+            name: "ConverterPlugin",
+            capability: .command(intent: .custom(verb: "convert", description: "Convert html content"), permissions: [.writeToPackageDirectory(reason: "The command needs the permission to create the converted file.")]),
+            dependencies: [
+                .target(name: "ConvertCommand")
+            ]
         )
     ]
 )
diff --git a/Plugins/ConverterPlugin/plugin.swift b/Plugins/ConverterPlugin/plugin.swift
new file mode 100644
index 00000000..6472d7c2
--- /dev/null
+++ b/Plugins/ConverterPlugin/plugin.swift
@@ -0,0 +1,74 @@
+import PackagePlugin
+import Foundation
+
+@main
+struct ConverterPlugin: CommandPlugin {
+    
+    func performCommand(context: PluginContext, arguments: [String]) async throws {
+        
+        let outputOptions = ["debug", "file"]
+        
+        let tool = try context.tool(named: "ConvertCommand")
+        
+        var extractor = ArgumentExtractor(arguments)
+        
+        let usageArgument = extractor.extractFlag(named: "command-usage")
+        
+        if usageArgument > 0 {
+            
+            let explanation = """
+            USAGE: convert --output-option <option> --source-path <path> --target-path <path>
+            
+            ARGUMENTS:
+                <output option> - file or debug
+                <source path> - The path, where the html files are located.
+                <target path> - The path, where the converted files should be saved into.
+            """
+            
+            print(explanation)
+            
+        } else {
+            
+            let outputArgument = extractor.extractOption(named: "output-option")
+            let sourceArgument = extractor.extractOption(named: "source-path")
+            let targetArgument = extractor.extractOption(named: "target-path")
+            
+            var processArguments = [String]()
+            
+            if let output = outputArgument.first {
+                
+                if !outputOptions.contains(output) {
+                    Diagnostics.error("Invalid output option. Choose 'file' or 'debug' instead.")
+                }
+                
+                processArguments.insert(output, at: 0)
+                
+            } else {
+                Diagnostics.error("Missing argument --output-option.")
+            }
+            
+            if let source = sourceArgument.first {
+                processArguments.insert(source, at: 1)
+                
+            } else {
+                Diagnostics.error("Missing argument --source-path.")
+            }
+            
+            if let target = targetArgument.first {
+                processArguments.insert(target, at: 2)
+            }
+            
+            print("The conversion starts...")
+            
+            let process = try Process.run(URL(fileURLWithPath: tool.path.string), arguments: processArguments)
+            process.waitUntilExit()
+            
+            if process.terminationReason == .exit && process.terminationStatus == 0 {
+                print("The conversion has finished.")
+                
+            } else {
+                Diagnostics.error("The conversion has failed: \(process.terminationReason)")
+            }
+        }
+    }
+}
diff --git a/Sources/Commands/Converter/ConvertCommand.swift b/Sources/Commands/Converter/ConvertCommand.swift
new file mode 100644
index 00000000..eb8b0efa
--- /dev/null
+++ b/Sources/Commands/Converter/ConvertCommand.swift
@@ -0,0 +1,69 @@
+import Foundation
+import Converter
+
+@main
+@available(macOS 11.0, *)
+internal struct ConvertCommand {
+    
+    private static var outputOption: String {
+        return CommandLine.arguments[1]
+    }
+    
+    private static var sourcePath: String {
+        return CommandLine.arguments[2]
+    }
+    
+    private static var targetPath: String? {
+        
+        if CommandLine.arguments.count < 4 {
+            return nil
+        }
+        
+        return CommandLine.arguments[3]
+    }
+    
+    internal static func main() throws {
+        
+        if !FileManager.default.fileExists(atPath: sourcePath) {
+            print("No valid source path.")
+            
+            exit(1)
+            
+        } else {
+            
+            let url = URL(fileURLWithPath: sourcePath)
+            
+            switch outputOption {
+            case "file":
+                
+                if let targetPath = self.targetPath {
+                    try Converter.default.convert(source: url, target: URL(fileURLWithPath: targetPath))
+                    
+                    exit(0)
+                    
+                } else {
+                    print("Unkown target path.")
+                    
+                    exit(1)
+                }
+                
+            case "debug":
+                
+                if targetPath != nil {
+                    print("Wrong output option.")
+                    
+                    exit(1)
+                    
+                } else {
+                    try Converter.default.convert(source: url)
+                    
+                    exit(0)
+                }
+                
+            default:
+                break
+                
+            }
+        }
+    }
+}
diff --git a/Sources/Converter/Converter.swift b/Sources/Converter/Converter.swift
new file mode 100644
index 00000000..632b7b04
--- /dev/null
+++ b/Sources/Converter/Converter.swift
@@ -0,0 +1,117 @@
+import Foundation
+
+#if canImport(FoundationXML)
+    import FoundationXML
+#endif
+
+@available(macOS 11.0, *)
+public class Converter {
+    
+    public enum ConverterError: Error {
+        case rootNotFound
+        case emptyFile
+    }
+    
+    public static let `default` = Converter()
+
+    private init() {}
+    
+    private func convert(content: String) throws -> String {
+        
+        let document = try XMLDocument(xmlString: content, options: [.documentIncludeContentTypeDeclaration])
+        
+        guard let root = document.rootElement() else {
+            throw ConverterError.rootNotFound
+        }
+        
+        return try Parser.shared.parse(node: root)
+    }
+    
+    public func convert(source path: URL) throws {
+        
+        if !path.hasDirectoryPath {
+            
+            let content = try String(contentsOf: path)
+            
+            if content.count > 1 {
+                print(try convert(content: content))
+                
+            } else {
+                throw ConverterError.emptyFile
+            }
+            
+        } else {
+            
+            if let enumerator = FileManager.default.enumerator(at: path, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]) {
+                
+                for case let path as URL in enumerator {
+                    
+                    if !path.hasDirectoryPath {
+                        
+                        if !path.isFileURL {
+                            enumerator.skipDescendants()
+                            
+                        } else {
+                            
+                            let content = try String(contentsOf: path)
+                            
+                            if content.count > 1 {
+                                print(try convert(content: content))
+                                
+                            } else {
+                                throw ConverterError.emptyFile
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    public func convert(source path: URL, target: URL) throws {
+        
+        if !path.hasDirectoryPath {
+            
+            let content = try String(contentsOf: path)
+            
+            if content.count > 1 {
+                
+                let result = try convert(content: content)
+                
+                try result.write(to: target, atomically: true, encoding: .utf8)
+                
+            } else {
+                throw ConverterError.emptyFile
+            }
+            
+        } else {
+         
+            if let enumerator = FileManager.default.enumerator(at: path, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]) {
+                
+                for case let path as URL in enumerator {
+                    
+                    if !path.hasDirectoryPath {
+
+                        if !path.isFileURL {
+                            enumerator.skipDescendants()
+                            
+                        } else {
+                            
+                            let content = try String(contentsOf: path)
+                            
+                            if content.count > 1 {
+                                
+                                let result = try convert(content: content)
+                                
+                                try result.write(to: target, atomically: true, encoding: .utf8)
+                                
+                            } else {
+                                throw ConverterError.emptyFile
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/Sources/Converter/InitRepresentable.swift b/Sources/Converter/InitRepresentable.swift
new file mode 100644
index 00000000..45b01311
--- /dev/null
+++ b/Sources/Converter/InitRepresentable.swift
@@ -0,0 +1,39 @@
+public protocol InitRepresentable {
+    
+    init?(value: String)
+}
+
+extension String: InitRepresentable {
+    
+    public init?(value: String) {
+        self.init(value)
+    }
+}
+
+extension Float: InitRepresentable {
+    
+    public init?(value: String) {
+        self.init(value)
+    }
+}
+
+extension Int: InitRepresentable {
+    
+    public init?(value: String) {
+        self.init(value)
+    }
+}
+
+extension Double: InitRepresentable {
+    
+    public init?(value: String) {
+        self.init(value)
+    }
+}
+
+extension Bool: InitRepresentable {
+    
+    public init?(value: String) {
+        self.init(value)
+    }
+}
diff --git a/Sources/Converter/Parser.swift b/Sources/Converter/Parser.swift
new file mode 100644
index 00000000..21a81b95
--- /dev/null
+++ b/Sources/Converter/Parser.swift
@@ -0,0 +1,1772 @@
+import HTMLKit
+import Foundation
+
+#if canImport(FoundationXML)
+import FoundationXML
+#endif
+
+internal class Parser {
+    
+    internal enum ParserError: Error {
+        
+        case noLocalName
+        case unkownElement(String)
+        case unkownAttribute(String)
+        case unknownTag(String)
+        
+        var description: String {
+            
+            switch self {
+            case .noLocalName:
+                return "No local name."
+                
+            case .unkownElement(let element):
+                return "Element '\(element) not found."
+                
+            case .unkownAttribute(let attribute):
+                return "Attribute '\(attribute) not found."
+                
+            case .unknownTag(let tag):
+                return "Tag '\(tag)' not found."
+            }
+        }
+    }
+    
+    internal static let shared = Parser()
+    
+    private init() {}
+    
+    internal func parse(node: XMLNode, indent: Int? = nil) throws -> String {
+        
+        switch node.kind {
+        case .text:
+            return TextElement(node: node).build()
+            
+        case .comment:
+            return CommentElement(node: node).build()
+            
+        case .element:
+            
+            if let element = node as? XMLElement {
+             
+                guard let localName = element.localName else {
+                    throw ParserError.noLocalName
+                }
+                
+                switch localName {
+                case "html":
+                    return try ContentElement(element: element).build()
+                    
+                case "head":
+                    return try ContentElement(element: element).build(verbatim: "Head")
+                    
+                case "body":
+                    return try ContentElement(element: element).build()
+                    
+                case "nav":
+                    return try ContentElement(element: element).build(verbatim: "Navigation")
+                    
+                case "link":
+                    return try EmptyElement(element: element).build()
+                    
+                case "aside":
+                    return try ContentElement(element: element).build()
+                    
+                case "section":
+                    return try ContentElement(element: element).build()
+                    
+                case "h1":
+                    return try ContentElement(element: element).build(verbatim: "Heading1")
+                    
+                case "h2":
+                    return try ContentElement(element: element).build(verbatim: "Heading2")
+                    
+                case "h3":
+                    return try ContentElement(element: element).build(verbatim: "Heading3")
+                    
+                case "h4":
+                    return try ContentElement(element: element).build(verbatim: "Heading4")
+                    
+                case "h5":
+                    return try ContentElement(element: element).build(verbatim: "Heading5")
+                    
+                case "h6":
+                    return try ContentElement(element: element).build(verbatim: "Heading6")
+                    
+                case "hgroup":
+                    return try ContentElement(element: element).build(verbatim: "HeadingGroup")
+                    
+                case "header":
+                    return try ContentElement(element: element).build()
+                    
+                case "footer":
+                    return try ContentElement(element: element).build()
+                    
+                case "address":
+                    return try ContentElement(element: element).build()
+                    
+                case "p":
+                    return try ContentElement(element: element).build(verbatim: "Paragraph")
+                    
+                case "hr":
+                    return try EmptyElement(element: element).build(verbatim: "HorizontalRule")
+                    
+                case "pre":
+                    return try ContentElement(element: element).build(verbatim: "PreformattedText")
+                    
+                case "blockquote":
+                    return try ContentElement(element: element).build()
+                    
+                case "ol":
+                    return try ContentElement(element: element).build(verbatim: "OrderedList")
+                    
+                case "ul":
+                    return try ContentElement(element: element).build(verbatim: "UnorderedList")
+                    
+                case "dl":
+                    return try ContentElement(element: element).build(verbatim: "DescriptionList")
+                    
+                case "figure":
+                    return try ContentElement(element: element).build()
+                    
+                case "a":
+                    return try ContentElement(element: element).build(verbatim: "Anchor")
+                    
+                case "em":
+                    return try ContentElement(element: element).build(verbatim: "Emphasize")
+                    
+                case "small":
+                    return try ContentElement(element: element).build()
+                    
+                case "s":
+                    return try ContentElement(element: element).build(verbatim: "StrikeThrough")
+                    
+                case "main":
+                    return try ContentElement(element: element).build()
+                    
+                case "div":
+                    return try ContentElement(element: element).build(verbatim: "Division")
+                    
+                case "dfn":
+                    return try ContentElement(element: element).build(verbatim: "Definition")
+                    
+                case "cite":
+                    return try ContentElement(element: element).build()
+                    
+                case "q":
+                    return try ContentElement(element: element).build(verbatim: "ShortQuote")
+                    
+                case "rt":
+                    return try ContentElement(element: element).build(verbatim: "RubyText")
+                    
+                case "rp":
+                    return try ContentElement(element: element).build(verbatim: "RubyPronunciation")
+                    
+                case "abbr":
+                    return try ContentElement(element: element).build(verbatim: "Abbreviation")
+                    
+                case "data":
+                    return try ContentElement(element: element).build()
+                    
+                case "time":
+                    return try ContentElement(element: element).build()
+                    
+                case "code":
+                    return try ContentElement(element: element).build()
+                    
+                case "v":
+                    return try ContentElement(element: element).build(verbatim: "Variable")
+                    
+                case "samp":
+                    return try ContentElement(element: element).build(verbatim: "SampleOutput")
+                    
+                case "kbd":
+                    return try ContentElement(element: element).build(verbatim: "KeyboardOutput")
+                    
+                case "sub":
+                    return try ContentElement(element: element).build(verbatim: "Subscript")
+                    
+                case "sup":
+                    return try ContentElement(element: element).build(verbatim: "Superscript")
+                    
+                case "i":
+                    return try ContentElement(element: element).build(verbatim: "Italic")
+                    
+                case "b":
+                    return try ContentElement(element: element).build(verbatim: "Bold")
+                    
+                case "strong":
+                    return try ContentElement(element: element).build(verbatim: "Strong")
+                    
+                case "u":
+                    return try ContentElement(element: element).build(verbatim: "SampleOutput")
+                    
+                case "mark":
+                    return try ContentElement(element: element).build()
+                    
+                case "bdi":
+                    return try ContentElement(element: element).build()
+                    
+                case "bdo":
+                    return try EmptyElement(element: element).build()
+                    
+                case "span":
+                    return try ContentElement(element: element).build()
+                    
+                case "br":
+                    return try EmptyElement(element: element).build(verbatim: "LineBreak")
+                    
+                case "wbr":
+                    return try EmptyElement(element: element).build(verbatim: "WordBreak")
+                    
+                case "ins":
+                    return try ContentElement(element: element).build(verbatim: "InsertedText")
+                    
+                case "del":
+                    return try ContentElement(element: element).build(verbatim: "DeletedText")
+                    
+                case "img":
+                    return try EmptyElement(element: element).build(verbatim: "Image")
+                    
+                case "embed":
+                    return try ContentElement(element: element).build()
+                    
+                case "iframe":
+                    return try ContentElement(element: element).build(verbatim: "InlineFrame")
+                    
+                case "param":
+                    return try EmptyElement(element: element).build(verbatim: "Parameter")
+                    
+                case "dt":
+                    return try ContentElement(element: element).build(verbatim: "TermName")
+                    
+                case "dd":
+                    return try ContentElement(element: element).build(verbatim: "TermDefinition")
+                    
+                case "figcaption":
+                    return try ContentElement(element: element).build(verbatim: "FigureCaption")
+                    
+                case "optgroup":
+                    return try ContentElement(element: element).build(verbatim: "OptionGroup")
+                    
+                case "option":
+                    return try ContentElement(element: element).build()
+                    
+                case "legend":
+                    return try ContentElement(element: element).build()
+                    
+                case "summary":
+                    return try ContentElement(element: element).build()
+                    
+                case "li":
+                    return try ContentElement(element: element).build(verbatim: "ListItem")
+                    
+                case "colgroup":
+                    return try ContentElement(element: element).build(verbatim: "ColumnGroup")
+                    
+                case "col":
+                    return try ContentElement(element: element).build(verbatim: "Column")
+                    
+                case "tbody":
+                    return try ContentElement(element: element).build(verbatim: "TableBody")
+                    
+                case "thead":
+                    return try ContentElement(element: element).build(verbatim: "TableHead")
+                    
+                case "tfoot":
+                    return try ContentElement(element: element).build(verbatim: "TableFoot")
+                    
+                case "tr":
+                    return try ContentElement(element: element).build(verbatim: "TableRow")
+                    
+                case "td":
+                    return try ContentElement(element: element).build(verbatim: "DataCell")
+                    
+                case "th":
+                    return try ContentElement(element: element).build(verbatim: "HeaderCell")
+                    
+                case "textarea":
+                    return try ContentElement(element: element).build(verbatim: "TextArea")
+                    
+                case "input":
+                    return try EmptyElement(element: element).build()
+                    
+                case "video":
+                    return try ContentElement(element: element).build()
+                    
+                case "audio":
+                    return try ContentElement(element: element).build()
+                    
+                case "map":
+                    return try ContentElement(element: element).build()
+                    
+                case "area":
+                    return try ContentElement(element: element).build()
+                    
+                case "form":
+                    return try ContentElement(element: element).build()
+                    
+                case "datalist":
+                    return try ContentElement(element: element).build()
+                    
+                case "output":
+                    return try ContentElement(element: element).build()
+                    
+                case "meter":
+                    return try ContentElement(element: element).build()
+                    
+                case "details":
+                    return try ContentElement(element: element).build()
+                    
+                case "dialog":
+                    return try ContentElement(element: element).build()
+                    
+                case "script":
+                    return try ContentElement(element: element).build()
+                    
+                case "noscript":
+                    return try ContentElement(element: element).build()
+                    
+                case "template":
+                    return try ContentElement(element: element).build()
+                    
+                case "canvas":
+                    return try ContentElement(element: element).build()
+                    
+                case "table":
+                    return try ContentElement(element: element).build()
+                    
+                case "fieldset":
+                    return try ContentElement(element: element).build()
+                    
+                case "button":
+                    return try ContentElement(element: element).build()
+                    
+                case "select":
+                    return try ContentElement(element: element).build()
+                    
+                case "label":
+                    return try ContentElement(element: element).build()
+                    
+                case "title":
+                    return try ContentElement(element: element).build()
+                    
+                case "base":
+                    return try EmptyElement(element: element).build()
+                    
+                case "meta":
+                    return try EmptyElement(element: element).build()
+                    
+                case "style":
+                    return try ContentElement(element: element).build()
+                    
+                case "source":
+                    return try EmptyElement(element: element).build()
+                    
+                case "track":
+                    return try EmptyElement(element: element).build()
+                    
+                case "article":
+                    return try ContentElement(element: element).build()
+                    
+                case "progress":
+                    return try ContentElement(element: element).build()
+                    
+                case "circle":
+                    return try ContentElement(element: element).build()
+                    
+                case "rect":
+                    return try ContentElement(element: element).build(verbatim: "Rectangle")
+                    
+                case "ellipse":
+                    return try ContentElement(element: element).build()
+                    
+                case "line":
+                    return try ContentElement(element: element).build()
+                    
+                case "polygon":
+                    return try ContentElement(element: element).build()
+                    
+                case "path":
+                    return try ContentElement(element: element).build()
+                    
+                case "use":
+                    return try ContentElement(element: element).build()
+                    
+                case "g":
+                    return try ContentElement(element: element).build(verbatim: "Group")
+                    
+                default:
+                    throw ParserError.unkownElement(localName)
+                }
+            }
+            
+        case .attribute:
+            
+            guard let localName = node.localName else  {
+                throw ParserError.noLocalName
+            }
+        
+            switch localName {
+            case "accesskey":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "accept":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "action":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "alt":
+                return try ValueAttribute<String>(node: node).build(verbatim: "alternate")
+                
+            case "async":
+                return try EmptyAttribute(node: node).build(verbatim: "asynchronously")
+                
+            case "autocapitalize":
+                return try TypeAttribute<Capitalization>(node: node).build()
+                
+            case "autocomplete":
+                return try ValueAttribute<Bool>(node: node).build(verbatim: "hasCompletion")
+                
+            case "autofocus":
+                return try EmptyAttribute(node: node).build()
+                
+            case "autoplay":
+                return try EmptyAttribute(node: node).build()
+                
+            case "checked":
+                return try EmptyAttribute(node: node).build()
+                
+            case "cite":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "class":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "cols":
+                return try ValueAttribute<Int>(node: node).build(verbatim: "columns")
+                
+            case "colspan":
+                return try ValueAttribute<Int>(node: node).build(verbatim: "columnSpan")
+                
+            case "content":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "contenteditable":
+                return try ValueAttribute<Bool>(node: node).build(verbatim: "isEditable")
+                
+            case "controls":
+                return try EmptyAttribute(node: node).build()
+                
+            case "coords":
+                return try ValueAttribute<String>(node: node).build(verbatim: "coordinates")
+                
+            case "data":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "datetime":
+                return try ValueAttribute<String>(node: node).build(verbatim: "dateTime")
+                
+            case "default":
+                return try EmptyAttribute(node: node).build()
+                
+            case "defer":
+                return try EmptyAttribute(node: node).build()
+                
+            case "dir":
+                return try TypeAttribute<Direction>(node: node).build(verbatim: "direction")
+                
+            case "disabled":
+                return try EmptyAttribute(node: node).build()
+                
+            case "download":
+                return try EmptyAttribute(node: node).build()
+                
+            case "draggable":
+                return try ValueAttribute<String>(node: node).build(verbatim: "isDraggable")
+                
+            case "enctype":
+                return try TypeAttribute<Encoding>(node: node).build(verbatim: "encoding")
+                
+            case "enterkeyhint":
+                return try TypeAttribute<Hint>(node: node).build(verbatim: "enterKeyHint")
+                
+            case "for":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "form":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "formaction":
+                return try ValueAttribute<String>(node: node).build(verbatim: "formAction")
+                
+            case "headers":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "height":
+                return try ValueAttribute<Int>(node: node).build()
+                
+            case "hidden":
+                return try EmptyAttribute(node: node).build()
+                
+            case "high":
+                return try ValueAttribute<Float>(node: node).build()
+                
+            case "href":
+                return try ValueAttribute<String>(node: node).build(verbatim: "reference")
+                
+            case "hreflang":
+                return try TypeAttribute<Language>(node: node).build(verbatim: "referenceLanguage")
+                
+            case "id":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "ismap":
+                return try EmptyAttribute(node: node).build(verbatim: "isMap")
+                
+            case "inputmode":
+                return try ValueAttribute<String>(node: node).build(verbatim: "inputMode")
+                
+            case "is":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "itemid":
+                return try ValueAttribute<String>(node: node).build(verbatim: "itemId")
+                
+            case "itemproperty":
+                return try ValueAttribute<String>(node: node).build(verbatim: "itemProperty")
+                
+            case "itemref":
+                return try ValueAttribute<String>(node: node).build(verbatim: "itemReference")
+                
+            case "itemscope":
+                return try ValueAttribute<String>(node: node).build(verbatim: "itemScope")
+                
+            case "itemtype":
+                return try ValueAttribute<String>(node: node).build(verbatim: "itemType")
+                
+            case "kind":
+                return try TypeAttribute<Kinds>(node: node).build()
+                
+            case "label":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "lang":
+                return try TypeAttribute<Language>(node: node).build(verbatim: "language")
+                
+            case "list":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "loop":
+                return try EmptyAttribute(node: node).build()
+                
+            case "low":
+                return try ValueAttribute<Float>(node: node).build()
+                
+            case "max":
+
+                if let parent = node.parent {
+                    
+                    switch parent.localName {
+                    case "progress", "meter":
+                        return try ValueAttribute<Float>(node: node).build(verbatim: "maximum")
+                        
+                    default:
+                        return try ValueAttribute<String>(node: node).build(verbatim: "maximum")
+                    }
+                }
+                
+            case "media":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "method":
+                return try TypeAttribute<HTMLKit.Method>(node: node).build()
+                
+            case "min":
+                return try ValueAttribute<String>(node: node).build(verbatim: "minimum")
+                
+            case "multiple":
+                return try EmptyAttribute(node: node).build()
+                
+            case "muted":
+                return try EmptyAttribute(node: node).build()
+                
+            case "name":
+                
+                if let parent = node.parent {
+                    
+                    switch parent.localName {
+                    case "meta":
+                        return try TypeAttribute<Names>(node: node).build()
+                        
+                    default:
+                        return try ValueAttribute<String>(node: node).build()
+                    }
+                }
+                
+            case "nonce":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "novalidate":
+                return try EmptyAttribute(node: node).build()
+                
+            case "open":
+                return try ValueAttribute<Bool>(node: node).build(verbatim: "isOpen")
+                
+            case "optimum":
+                return try ValueAttribute<Float>(node: node).build()
+                
+            case "pattern":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "part":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "ping":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "placeholder":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "poster":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "preload":
+                return try TypeAttribute<Preload>(node: node).build()
+                
+            case "readonly":
+                return try EmptyAttribute(node: node).build()
+                
+            case "referrerpolicy":
+                return try TypeAttribute<Policy>(node: node).build(verbatim: "referrerPolicy")
+                
+            case "rel":
+                return try TypeAttribute<Relation>(node: node).build(verbatim: "relationship")
+                
+            case "required":
+                return try EmptyAttribute(node: node).build()
+                
+            case "reversed":
+                return try EmptyAttribute(node: node).build()
+                
+            case "role":
+                return try TypeAttribute<Roles>(node: node).build()
+                
+            case "rows":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "rowspan":
+                return try ValueAttribute<Int>(node: node).build(verbatim: "rowSpan")
+                
+            case "sandbox":
+                return try EmptyAttribute(node: node).build()
+                
+            case "scope":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "shape":
+                return try TypeAttribute<Shape>(node: node).build()
+                
+            case "size":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "sizes":
+                return try ValueAttribute<Int>(node: node).build()
+                
+            case "slot":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "span":
+                return try ValueAttribute<Int>(node: node).build()
+                
+            case "spellcheck":
+                return try ValueAttribute<Bool>(node: node).build(verbatim: "hasSpellCheck")
+                
+            case "src":
+                return try ValueAttribute<String>(node: node).build(verbatim: "source")
+                
+            case "start":
+                return try ValueAttribute<Int>(node: node).build()
+                
+            case "step":
+                return try ValueAttribute<Int>(node: node).build()
+                
+            case "style":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "tabindex":
+                return try ValueAttribute<Int>(node: node).build(verbatim: "tabIndex")
+                
+            case "target":
+                return try TypeAttribute<Target>(node: node).build()
+                
+            case "title":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "translate":
+                return try TypeAttribute<Decision>(node: node).build()
+                
+            case "type":
+
+                if let parent = node.parent {
+                    
+                    switch parent.localName {
+                        
+                    case "input":
+                        return try TypeAttribute<Inputs>(node: node).build()
+                        
+                    case "button":
+                        return try TypeAttribute<Buttons>(node: node).build()
+                        
+                    case "link", "script", "audio":
+                        return try TypeAttribute<Medias>(node: node).build()
+                        
+                    default:
+                        return try ValueAttribute<String>(node: node).build()
+                    }
+                }
+                
+            case "value":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "width":
+                return try ValueAttribute<Int>(node: node).build()
+                
+            case "wrap":
+                return try TypeAttribute<Wrapping>(node: node).build()
+                
+            case "property":
+                return try TypeAttribute<Graphs>(node: node).build()
+                
+            case "charset":
+                return try TypeAttribute<Charset>(node: node).build()
+                
+            case "http-equiv":
+                return try TypeAttribute<Equivalent>(node: node).build()
+                
+            case "selected":
+                return try EmptyAttribute(node: node).build()
+                
+            case "maxlength":
+                return try ValueAttribute<String>(node: node).build(verbatim: "maximum")
+                
+            case "minlength":
+                return try ValueAttribute<String>(node: node).build(verbatim: "minimum")
+                
+            case "d":
+                return try ValueAttribute<String>(node: node).build(verbatim: "draw")
+                
+            case "fill":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "fill-opacity":
+                return try ValueAttribute<Double>(node: node).build(verbatim: "fillOpacity")
+                
+            case "stroke":
+                return try ValueAttribute<String>(node: node).build()
+                
+            case "stroke-width":
+                return try ValueAttribute<Int>(node: node).build(verbatim: "strokeWidth")
+                
+            case "stroke-opacity":
+                return try ValueAttribute<Double>(node: node).build(verbatim: "strokeOpacity")
+                
+            case "stroke-linecap":
+                return try TypeAttribute<Linecap>(node: node).build(verbatim: "strokeLineCap")
+                
+            case "stroke-linejoin":
+                return try TypeAttribute<Linejoin>(node: node).build(verbatim: "strokeLineJoin")
+                
+            case "r":
+                return try ValueAttribute<Int>(node: node).build(verbatim: "radius")
+                
+            case "viewbox":
+                return try ValueAttribute<String>(node: node).build(verbatim: "viewBox")
+                
+            case "onafterprint":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onbeforeprint":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onbeforeunload":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onhashchange":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onlanguagechange":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onmessage":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onmessageerror":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onoffline":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "ononline":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onpagehide":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onpageshow":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onpopstate":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onrejectionhandled":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onstorage":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onunhandledrejection":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onunload":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onerror":
+                return try EventAttribute<Events.Window>(node: node).build()
+                
+            case "onblur":
+                return try EventAttribute<Events.Focus>(node: node).build()
+                
+            case "onfocus":
+                return try EventAttribute<Events.Focus>(node: node).build()
+                
+            case "onpointercancel":
+                return try EventAttribute<Events.Pointer>(node: node).build()
+                
+            case "onpointerdown":
+                return try EventAttribute<Events.Pointer>(node: node).build()
+                
+            case "onpointerenter":
+                return try EventAttribute<Events.Pointer>(node: node).build()
+                
+            case "onpointerleave":
+                return try EventAttribute<Events.Pointer>(node: node).build()
+                
+            case "onpointermove":
+                return try EventAttribute<Events.Pointer>(node: node).build()
+                
+            case "onpointerout":
+                return try EventAttribute<Events.Pointer>(node: node).build()
+                
+            case "onpointerover":
+                return try EventAttribute<Events.Pointer>(node: node).build()
+                
+            case "onpointerup":
+                return try EventAttribute<Events.Pointer>(node: node).build()
+                
+            case "onlostpointercapture":
+                return try EventAttribute<Events.Pointer>(node: node).build()
+                
+            case "onclick":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "oncontextmenu":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "ondblclick":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "onmousedown":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "onmouseenter":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "onmouseleave":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "onmousemove":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "onmouseout":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "onmouseover":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "onmouseup":
+                return try EventAttribute<Events.Mouse>(node: node).build()
+                
+            case "onwheel":
+                return try EventAttribute<Events.Wheel>(node: node).build()
+                
+            case "onbeforeinput":
+                return try EventAttribute<Events.Input>(node: node).build()
+                
+            case "oninput":
+                return try EventAttribute<Events.Input>(node: node).build()
+                
+            case "onselect":
+                return try EventAttribute<Events.Input>(node: node).build()
+                
+            case "onkeydown":
+                return try EventAttribute<Events.Keyboard>(node: node).build()
+                
+            case "onkeyup":
+                return try EventAttribute<Events.Keyboard>(node: node).build()
+                
+            case "ondrag":
+                return try EventAttribute<Events.Drag>(node: node).build()
+                
+            case "ondragend":
+                return try EventAttribute<Events.Drag>(node: node).build()
+                
+            case "ondragenter":
+                return try EventAttribute<Events.Drag>(node: node).build()
+                
+            case "ondragleave":
+                return try EventAttribute<Events.Drag>(node: node).build()
+                
+            case "ondragover":
+                return try EventAttribute<Events.Drag>(node: node).build()
+                
+            case "ondragstart":
+                return try EventAttribute<Events.Drag>(node: node).build()
+                
+            case "ondrop":
+                return try EventAttribute<Events.Drag>(node: node).build()
+                
+            case "oncopy":
+                return try EventAttribute<Events.Clipboard>(node: node).build()
+                
+            case "oncut":
+                return try EventAttribute<Events.Clipboard>(node: node).build()
+                
+            case "onpaste":
+                return try EventAttribute<Events.Clipboard>(node: node).build()
+                
+            case "onselectionchange":
+                return try EventAttribute<Events.Selection>(node: node).build()
+                
+            case "onselectstart":
+                return try EventAttribute<Events.Selection>(node: node).build()
+                
+            case "onabort":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "oncanplay":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "oncanplaythrough":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "ondurationchange":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onemptied":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onended":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onplay":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onplaying":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onpause":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onratechange":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onseeked":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onseeking":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onstalled":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onsuspend":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "ontimeupdate":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onvolumechange":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onwaiting":
+                return try EventAttribute<Events.Media>(node: node).build()
+                
+            case "onreset":
+                return try EventAttribute<Events.Form>(node: node).build()
+                
+            case "onsubmit":
+                return try EventAttribute<Events.Form>(node: node).build()
+                
+            case "ontoggle":
+                return try EventAttribute<Events.Detail>(node: node).build()
+                
+            case "aria-activedescendant":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "activeDescendant")
+                
+            case "aria-atomic":
+                return try ValueAttribute<Bool>(node: node, kind: .aria).build(verbatim: "atomic")
+                
+            case "aria-autocomplete":
+                return try TypeAttribute<Accessibility.Complete>(node: node, kind: .aria).build(verbatim: "autoComplete")
+                
+            case "aria-busy":
+                return try ValueAttribute<Bool>(node: node, kind: .aria).build(verbatim: "busy")
+                
+            case "aria-checked":
+                return try TypeAttribute<Accessibility.Check>(node: node, kind: .aria).build(verbatim: "checked")
+                
+            case "aria-colcount":
+                return try ValueAttribute<Int>(node: node, kind: .aria).build(verbatim: "columnCount")
+                
+            case "aria-colindex":
+                return try ValueAttribute<Int>(node: node, kind: .aria).build(verbatim: "columnIndex")
+                
+            case "aria-colspan":
+                return try ValueAttribute<Int>(node: node, kind: .aria).build(verbatim: "columnSpan")
+                
+            case "aria-controls":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "controls")
+                
+            case "aria-current":
+                return try TypeAttribute<Accessibility.Current>(node: node, kind: .aria).build(verbatim: "current")
+                
+            case "aria-describedby":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "describedBy")
+                
+            case "aria-details":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "details")
+                
+            case "aria-disabled":
+                return try ValueAttribute<Bool>(node: node, kind: .aria).build(verbatim: "disabled")
+                
+            case "aria-errormessage":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "errorMessage")
+                
+            case "aria-expanded":
+                return try ValueAttribute<Bool>(node: node, kind: .aria).build(verbatim: "expanded")
+                
+            case "aria-flowto":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "flowTo")
+                
+            case "aria-haspopup":
+                return try TypeAttribute<Accessibility.Popup>(node: node, kind: .aria).build(verbatim: "hasPopup")
+                
+            case "aria-hidden":
+                return try ValueAttribute<Bool>(node: node).build(verbatim: "hidden")
+                
+            case "aria-invalid":
+                return try TypeAttribute<Accessibility.Invalid>(node: node, kind: .aria).build(verbatim: "invalid")
+                
+            case "aria-keyshortcuts":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "keyShortcuts")
+                
+            case "aria-label":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "label")
+                
+            case "aria-labeledby":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "labeledBy")
+                
+            case "aria-level":
+                return try ValueAttribute<Int>(node: node, kind: .aria).build(verbatim: "level")
+                
+            case "aria-live":
+                return try TypeAttribute<Accessibility.Live>(node: node, kind: .aria).build(verbatim: "live")
+                
+            case "aria-modal":
+                return try ValueAttribute<Bool>(node: node, kind: .aria).build(verbatim: "modal")
+                
+            case "aria-multiline":
+                return try ValueAttribute<Bool>(node: node, kind: .aria).build(verbatim: "multiline")
+                
+            case "aria-multiselectable":
+                return try ValueAttribute<Bool>(node: node, kind: .aria).build(verbatim: "multiselectable")
+                
+            case "aria-orientation":
+                return try TypeAttribute<Accessibility.Orientation>(node: node, kind: .aria).build(verbatim: "orientation")
+                
+            case "aria-owns":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "owns")
+                
+            case "aria-placeholder":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "placeholder")
+                 
+            case "aria-posinset":
+                return try ValueAttribute<Int>(node: node, kind: .aria).build(verbatim: "positionIndex")
+                
+            case "aria-pressed":
+                return try TypeAttribute<Accessibility.Pressed>(node: node, kind: .aria).build(verbatim: "pressed")
+                
+            case "aria-readonly":
+                return try ValueAttribute<Bool>(node: node, kind: .aria).build(verbatim: "readonly")
+                
+            case "aria-relevant":
+                return try TypeAttribute<Accessibility.Relevant>(node: node, kind: .aria).build(verbatim: "relevant")
+                
+            case "aria-required":
+                return try ValueAttribute<Bool>(node: node, kind: .aria).build(verbatim: "required")
+                
+            case "aria-roledescription":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "roleDescription")
+                
+            case "aria-rowcount":
+                return try ValueAttribute<Int>(node: node, kind: .aria).build(verbatim: "rowCount")
+                
+            case "aria-rowindex":
+                return try ValueAttribute<Int>(node: node, kind: .aria).build(verbatim: "rowIndex")
+                
+            case "aria-rowspan":
+                return try ValueAttribute<Int>(node: node, kind: .aria).build(verbatim: "rowSpan")
+                
+            case "aria-selected":
+                return try TypeAttribute<Accessibility.Selected>(node: node, kind: .aria).build(verbatim: "selected")
+                
+            case "aria-setsize":
+                return try ValueAttribute<Int>(node: node, kind: .aria).build(verbatim: "setSize")
+                
+            case "aria-sort":
+                return try TypeAttribute<Accessibility.Sort>(node: node, kind: .aria).build(verbatim: "sort")
+                
+            case "aria-valuemax":
+                return try ValueAttribute<Float>(node: node, kind: .aria).build(verbatim: "valueMaximum")
+                
+            case "aria-valuemin":
+                return try ValueAttribute<Float>(node: node, kind: .aria).build(verbatim: "valueMinimum")
+                
+            case "aria-valuenow":
+                return try ValueAttribute<Float>(node: node, kind: .aria).build(verbatim: "valueNow")
+                
+            case "aria-valuetext":
+                return try ValueAttribute<String>(node: node, kind: .aria).build(verbatim: "valueText")
+                
+            default:
+                throw ParserError.unkownAttribute(localName)
+            }
+            
+        default:
+            break
+        }
+        
+        return ""
+    }
+    
+    internal struct PageLayout<T: RawRepresentable> {
+        
+        private let name: String
+        
+        private var content: String {
+            
+            get throws {
+                return try Parser.shared.parse(node: element)
+            }
+        }
+        
+        private var type: String {
+            
+            if let name = doctype.name, let publicId = doctype.publicID, let systemId = doctype.systemID {
+                
+                if let type = T(rawValue: "\(name) PUBLIC \"\(publicId)\" \"\(systemId)\"" as! T.RawValue) {
+                    return ".\(type)"
+                }
+            }
+            
+            return ".html5"
+        }
+        
+        private let doctype: XMLDTD
+        
+        private let element: XMLElement
+        
+        internal init(name: String, doctype: XMLDTD, element: XMLElement) {
+            self.name = name.capitalized
+            self.doctype = doctype
+            self.element = element
+        }
+        
+        internal func build() throws -> String {
+            
+            return """
+            import HTMLKit
+            
+            struct \(name)Page: Page {
+            
+                public var body: AnyContent {
+                    Document(type: \(type))
+            \(try content)
+                }
+            }
+            """
+        }
+    }
+
+    internal struct ViewLayout {
+        
+        private let name: String
+        
+        private var content: String {
+
+            get throws {
+                return try Parser.shared.parse(node: element)
+            }
+        }
+        
+        private let element: XMLElement
+        
+        internal init(name: String, element: XMLElement) {
+            self.name = name.capitalized
+            self.element = element
+        }
+        
+        internal func build() throws -> String {
+            
+            return """
+            import HTMLKit
+            
+            struct \(name)View: View {
+            
+                @TemplateValue(String.self) var context
+            
+                public var body: AnyContent {
+            \(try content)
+                }
+            }
+            """
+        }
+    }
+    
+    internal struct CommentElement {
+        
+        private var value: String? {
+            
+            guard let value = node.stringValue else {
+                return nil
+            }
+            
+            return value
+        }
+        
+        private var level: Int {
+            return node.level - 1
+        }
+        
+        private let node: XMLNode
+        
+        internal init(node: XMLNode) {
+            self.node = node
+        }
+        
+        internal func build(preindent: Int = 0) -> String {
+            
+            let indent = String(repeating: "\t", count: (level + preindent))
+            
+            if let value = value {
+                return "\(indent)Comment(\"\(value)\")\n"
+            }
+            
+            return "\(indent)Comment(\"\")\n"
+        }
+    }
+
+    internal struct TextElement {
+        
+        private var value: String? {
+            
+            guard let value = node.stringValue else {
+                return nil
+            }
+            
+            return value
+        }
+        
+        private var level: Int {
+            return node.level - 1
+        }
+        
+        private let node: XMLNode
+        
+        internal init(node: XMLNode) {
+            self.node = node
+        }
+        
+        internal func build(preindent: Int = 0) -> String {
+            
+            let indent = String(repeating: "\t", count: (level + preindent))
+            
+            if let value = value {
+                return "\(indent)\"\(value)\"\n"
+            }
+            
+            return "\(indent)\"\"\n"
+        }
+    }
+
+    internal struct ContentElement {
+
+        private var name: String {
+            
+            get throws {
+                
+                guard let name = element.name else {
+                    throw ParserError.noLocalName
+                }
+            
+                return name.capitalized
+            }
+        }
+        
+        private var attributes: [String]? {
+            
+            get throws {
+                
+                guard let attributes = element.attributes else {
+                    return nil
+                }
+                
+                return try attributes.map { attribute in
+                    return try Parser.shared.parse(node: attribute)
+                }
+            }
+        }
+        
+        private var content: [String]? {
+            
+            get throws {
+                
+                guard let children = element.children else {
+                    return nil
+                }
+                
+                return try children.compactMap { child in
+                    return try Parser.shared.parse(node: child)
+                }
+            }
+        }
+        
+        private var level: Int {
+            return element.level - 1
+        }
+        
+        private let element: XMLElement
+        
+        internal init(element: XMLElement) {
+            self.element = element
+        }
+        
+        internal func build(preindent: Int = 0) throws -> String {
+            
+            let indent = String(repeating: "\t", count: (level + preindent))
+            
+            var yield: String = ""
+            
+            yield += "\(indent)\(try name) {\n"
+
+            if let content = try content {
+                yield += content.joined()
+            }
+            
+            yield += "\(indent)}\n"
+            
+            if let attributes = try attributes {
+                yield += "\(indent)\(attributes.joined(separator: "\(indent)"))"
+            }
+            
+            return yield
+        }
+        
+        internal func build(verbatim: String, preindent: Int = 0) throws -> String {
+            
+            let indent = String(repeating: "\t", count: (level + preindent))
+            
+            var yield: String = ""
+            
+            yield += "\(indent)\(verbatim) {\n"
+
+            if let content = try content {
+                yield += content.joined()
+            }
+            
+            yield += "\(indent)}\n"
+            
+            if let attributes = try attributes {
+                yield += "\(indent)\(attributes.joined(separator: "\(indent)"))"
+            }
+            
+            return yield
+        }
+    }
+
+    internal struct EmptyElement {
+
+        private var name: String {
+            
+            get throws {
+                
+                guard let name = element.name else {
+                    throw ParserError.noLocalName
+                }
+            
+                return name.capitalized
+            }
+        }
+        
+        private var attributes: [String]? {
+            
+            get throws {
+                
+                guard let attributes = element.attributes else {
+                    return nil
+                }
+                
+                return try attributes.map { attribute in
+                    return try Parser.shared.parse(node: attribute)
+                }
+            }
+        }
+        
+        private var level: Int {
+            return element.level - 1
+        }
+        
+        private let element: XMLElement
+        
+        internal init(element: XMLElement) {
+            self.element = element
+        }
+        
+        internal func build(preindent: Int = 0) throws -> String {
+
+            let indent = String(repeating: "\t", count: (level + preindent))
+            
+            var yield: String = ""
+            
+            yield += "\(indent)\(try name)()\n"
+            
+            if let attributes = try attributes {
+                yield += "\(indent)\t\(attributes.joined(separator: "\t\(indent)"))"
+            }
+            
+            return yield
+        }
+        
+        internal func build(verbatim: String, preindent: Int = 0) throws -> String {
+
+            let indent = String(repeating: "\t", count: (level + preindent))
+
+            var yield: String = ""
+            
+            yield += "\(indent)\(verbatim)()\n"
+            
+            if let attributes = try attributes {
+                yield += "\(indent)\t\(attributes.joined(separator: "\t\(indent)"))"
+            }
+            
+            return yield
+        }
+    }
+    
+    internal struct ValueAttribute<T: InitRepresentable> {
+        
+        internal enum AttributeKind {
+            case normal
+            case aria
+        }
+        
+        private var kind: AttributeKind
+        
+        private var name: String {
+            
+            get throws {
+                
+                guard let name = node.name else {
+                    throw ParserError.noLocalName
+                }
+                
+                return name
+            }
+        }
+        
+        private var value: T? {
+            
+            guard let value = node.stringValue else {
+                return nil
+            }
+            
+            return T(value: value)
+        }
+        
+        private let node: XMLNode
+        
+        internal init(node: XMLNode, kind: AttributeKind = .normal) {
+            self.node = node
+            self.kind = kind
+        }
+        
+        internal func build() throws -> String {
+
+            switch kind {
+            case .normal:
+                
+                if let value = self.value {
+                    
+                    switch value {
+                    case is Float, is Int, is Double, is Bool:
+                        return ".\(try name)(\(value))\n"
+                        
+                    default:
+                        return ".\(try name)(\"\(value)\")\n"
+                    }
+                }
+                
+                return ".\(try name)()\n"
+                
+            case .aria:
+                
+                if let value = self.value {
+                    
+                    switch value {
+                    case is Float, is Int, is Double, is Bool:
+                        return ".aria(\(try name): \(value))\n"
+                        
+                    default:
+                        return ".aria(\(try name): \"\(value)\")\n"
+                    }
+                }
+                
+                return ".aria(\(try name): \"\")\n"
+            }
+        }
+        
+        internal func build(verbatim: String) throws -> String {
+
+            switch kind {
+            case .normal:
+                
+                if let value = value {
+                    
+                    switch value {
+                    case is Float, is Int, is Double, is Bool:
+                        return ".\(verbatim)(\(value))\n"
+                        
+                    default:
+                        return ".\(verbatim)(\"\(value)\")\n"
+                    }
+                }
+                
+                return ".\(verbatim)()\n"
+                
+            case .aria:
+                
+                if let value = value {
+                    
+                    switch value {
+                    case is Float, is Int, is Double, is Bool:
+                        return ".aria(\(verbatim): \(value))\n"
+                        
+                    default:
+                        return ".aria(\(verbatim): \"\(value)\")\n"
+                    }
+                }
+                
+                return ".aria(\(verbatim): \"\")\n"
+            }
+        }
+    }
+
+    internal struct EmptyAttribute {
+        
+        private var name: String {
+            
+            get throws {
+                
+                guard let name = node.name else {
+                    throw ParserError.noLocalName
+                }
+                
+                return name
+            }
+        }
+        
+        private let node: XMLNode
+        
+        internal init(node: XMLNode) {
+            self.node = node
+        }
+        
+        internal func build() throws -> String {
+            return ".\(try name)()\n"
+        }
+        
+        internal func build(verbatim: String) throws -> String {
+            return ".\(verbatim)()\n"
+        }
+    }
+
+    internal struct TypeAttribute<T: RawRepresentable> {
+        
+        internal enum AttributeKind {
+            case normal
+            case aria
+        }
+        
+        private var kind: AttributeKind
+        
+        private var name: String {
+            
+            get throws {
+                
+                guard let name = node.name else {
+                    throw ParserError.noLocalName
+                }
+                
+                return name
+            }
+        }
+        
+        private var value: T? {
+
+            guard let value = node.stringValue  else {
+                return nil
+            }
+            
+            return T(rawValue: value.lowercased() as! T.RawValue)
+        }
+        
+        private let node: XMLNode
+        
+        internal init(node: XMLNode, kind: AttributeKind = .normal) {
+            self.node = node
+            self.kind = kind
+        }
+        
+        internal func build() throws -> String {
+
+            switch kind {
+            case .normal:
+                
+                if let value = value {
+                    return ".\(try name)(.\(value))\n"
+                }
+                
+                return ".\(try name)()\n"
+                
+            case .aria:
+                
+                if let value = value {
+                    return ".aria(\(try name): .\(value))\n"
+                }
+                
+                return ".aria(\(try name): \"\")\n"
+            }
+        }
+        
+        internal func build(verbatim: String) throws -> String {
+
+            switch kind {
+            case .normal:
+                
+                if let value = value {
+                    return ".\(verbatim)(.\(value))\n"
+                }
+                
+                return ".\(verbatim)()\n"
+                
+            case .aria:
+                
+                if let value = value {
+                    return ".aria(\(verbatim): .\(value))\n"
+                }
+                
+                return ".aria(\(verbatim): \"\")\n"
+            }
+        }
+    }
+
+    internal struct CustomAttribute {
+        
+        private var name: String {
+            
+            get throws {
+                
+                guard let name = node.name else {
+                    throw ParserError.noLocalName
+                }
+                
+                return name
+            }
+        }
+        
+        private var value: String? {
+            
+            guard let value = node.stringValue else {
+                return nil
+            }
+            
+            return value
+        }
+        
+        private let node: XMLNode
+        
+        internal init(node: XMLNode) {
+            self.node = node
+        }
+        
+        internal func build() throws -> String {
+            
+            if let value = value {
+                return ".custom(key: \"\(try name)\", value: \"\(value)\")\n"
+            }
+            
+            return ".custom(key: \"\(try name)\", value: \"\")\n"
+        }
+    }
+
+    internal struct EventAttribute<T: RawRepresentable> {
+        
+        private var name: T {
+
+            get throws {
+             
+                guard let name = T(rawValue: node.localName?.lowercased() as! T.RawValue)  else {
+                    throw ParserError.noLocalName
+                }
+                
+                return name
+            }
+        }
+        
+        private var value: String? {
+            
+            guard let value = node.stringValue else {
+                return nil
+            }
+            
+            return value
+        }
+        
+        private let node: XMLNode
+        
+        internal init(node: XMLNode) {
+            self.node = node
+        }
+        
+        internal func build() throws -> String {
+            
+            if let value = value {
+                return ".on(event: .\(try name), \"\(value)\")\n"
+            }
+            
+            return ".on(event: .\(try name), \"\")\n"
+        }
+    }
+}
diff --git a/Sources/HTMLKit/Internal/Features/Conversion/Converter.swift b/Sources/HTMLKit/Internal/Features/Conversion/Converter.swift
deleted file mode 100644
index 31e1f913..00000000
--- a/Sources/HTMLKit/Internal/Features/Conversion/Converter.swift
+++ /dev/null
@@ -1,1506 +0,0 @@
-/*
- Abstract:
- The file contains the converter.
- 
- Authors:
- - Mats Moll (https://github.com/matsmoll)
- 
- Contributors:
- - Mattes Mohr (https://github.com/mattesmohr)
- 
- Note:
- If you about to add something to the file, stick to the official documentation to keep the code consistent.
- */
-
-import Foundation
- #if canImport(FoundationXML)
- import FoundationXML
- #endif
-
-@available(macOS 11.0, *)
-public class Converter {
-    
-    public enum Extension: String {
-        case html
-        case leaf
-    }
-    
-    public enum Output: String {
-        case print
-        case file
-    }
-    
-    public enum Errors: Error {
-        case rootNotFound
-    }
-    
-    public static let `default` = Converter()
-
-    private init() {}
-    
-    public func convert(directory: URL, fileExtension: Extension = .html, option: Output) throws {
-        
-        if let enumerator = FileManager.default.enumerator(at: directory, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]) {
-            
-            for case let path as URL in enumerator {
-                
-                if !path.hasDirectoryPath {
-
-                    if path.pathExtension != fileExtension.rawValue {
-                        enumerator.skipDescendants()
-                    } else {
-                        try convert(file: path, option: option)
-                    }
-                    
-                }
-            }
-        }
-    }
-
-    public func convert(file: URL, option: Output) throws {
-        
-        let fileName = file.deletingPathExtension().lastPathComponent
-        
-        let document = try XMLDocument(contentsOf: file, options: [.documentIncludeContentTypeDeclaration])
-        
-        guard let root = document.rootElement() else {
-            throw Errors.rootNotFound
-        }
-        
-        switch option {
-        case .print:
-            
-            if let dtd = document.dtd {
-                
-                let layout = PageLayout<Doctypes>(name: fileName, doctype: dtd, root: root).build()
-                
-                print(layout)
-                
-            } else {
-                
-                let layout = ViewLayout(name: fileName, root: root).build()
-                
-                print(layout)
-            }
-            
-        case .file:
-            
-            if let dtd = document.dtd {
-                
-                let layout = PageLayout<Doctypes>(name: fileName, doctype: dtd, root: root).build()
-                
-                try layout.write(to: file.deletingPathExtension().appendingPathExtension("swift"),
-                              atomically: true,
-                              encoding: .utf8)
-                
-            } else {
-                
-                let layout = ViewLayout(name: fileName, root: root).build()
-                
-                try layout.write(to: file.deletingPathExtension().appendingPathExtension("swift"),
-                              atomically: true,
-                              encoding: .utf8)
-            }
-        }
-    }
-    
-    /// Converts an HTML component to be put into an existing Page or View layout.
-    /// 
-    /// The whole html string needs to be inside a tag.
-    /// For example, multiple `div`s will give an error. They need to be inside another `div`.
-    public func convert(html: String) throws -> String {
-        
-        let document = try XMLDocument(xmlString: html, options: [.documentIncludeContentTypeDeclaration])
-        
-        guard let root = document.rootElement() else {
-            throw Errors.rootNotFound
-        }
-        
-        let content = Converter.default.decode(element: root)
-        
-        // The user would put this to a line that's already indented. So, remove the extra indentation:
-        return content.replacingOccurrences(of: "\t\t\t", with: "\t")
-    }
-    
-    @StringBuilder private func decode(attribute: XMLNode) -> String {
-        
-        switch attribute.localName {
-        case "accesskey":
-            ValueProperty<String>(node: attribute).build()
-        case "accept":
-            ValueProperty<String>(node: attribute).build()
-        case "action":
-            ValueProperty<String>(node: attribute).build()
-        case "alt":
-            ValueProperty<String>(node: attribute).build(verbatim: "alternate")
-        case "async":
-            EmptyProperty(node: attribute).build(verbatim: "asynchronously")
-        case "autocapitalize":
-            TypeProperty<Capitalization>(node: attribute).build()
-        case "autocomplete":
-            ValueProperty<Bool>(node: attribute).build(verbatim: "hasCompletion")
-        case "autofocus":
-            EmptyProperty(node: attribute).build()
-        case "autoplay":
-            EmptyProperty(node: attribute).build()
-        case "checked":
-            EmptyProperty(node: attribute).build()
-        case "cite":
-            ValueProperty<String>(node: attribute).build()
-        case "class":
-            ValueProperty<String>(node: attribute).build()
-        case "cols":
-            ValueProperty<Int>(node: attribute).build(verbatim: "columns")
-        case "colspan":
-            ValueProperty<Int>(node: attribute).build(verbatim: "columnSpan")
-        case "content":
-            ValueProperty<String>(node: attribute).build()
-        case "contenteditable":
-            ValueProperty<Bool>(node: attribute).build(verbatim: "isEditable")
-        case "controls":
-            EmptyProperty(node: attribute).build()
-        case "coords":
-            ValueProperty<String>(node: attribute).build(verbatim: "coordinates")
-        case "data":
-            ValueProperty<String>(node: attribute).build()
-        case "datetime":
-            ValueProperty<String>(node: attribute).build(verbatim: "dateTime")
-        case "default":
-            EmptyProperty(node: attribute).build()
-        case "defer":
-            EmptyProperty(node: attribute).build()
-        case "dir":
-            TypeProperty<Direction>(node: attribute).build(verbatim: "direction")
-        case "disabled":
-            EmptyProperty(node: attribute).build()
-        case "download":
-            EmptyProperty(node: attribute).build()
-        case "draggable":
-            ValueProperty<String>(node: attribute).build(verbatim: "isDraggable")
-        case "enctype":
-            TypeProperty<Encoding>(node: attribute).build(verbatim: "encoding")
-        case "enterkeyhint":
-            TypeProperty<Hint>(node: attribute).build(verbatim: "enterKeyHint")
-        case "for":
-            ValueProperty<String>(node: attribute).build()
-        case "form":
-            ValueProperty<String>(node: attribute).build()
-        case "formaction":
-            ValueProperty<String>(node: attribute).build(verbatim: "formAction")
-        case "headers":
-            ValueProperty<String>(node: attribute).build()
-        case "height":
-            ValueProperty<Int>(node: attribute).build()
-        case "hidden":
-            EmptyProperty(node: attribute).build()
-        case "high":
-            ValueProperty<Float>(node: attribute).build()
-        case "href":
-            ValueProperty<String>(node: attribute).build(verbatim: "reference")
-        case "hreflang":
-            TypeProperty<Language>(node: attribute).build(verbatim: "referenceLanguage")
-        case "id":
-            ValueProperty<String>(node: attribute).build()
-        case "ismap":
-            EmptyProperty(node: attribute).build(verbatim: "isMap")
-        case "inputmode":
-            ValueProperty<String>(node: attribute).build(verbatim: "inputMode")
-        case "is":
-            ValueProperty<String>(node: attribute).build()
-        case "itemid":
-            ValueProperty<String>(node: attribute).build(verbatim: "itemId")
-        case "itemproperty":
-            ValueProperty<String>(node: attribute).build(verbatim: "itemProperty")
-        case "itemref":
-            ValueProperty<String>(node: attribute).build(verbatim: "itemReference")
-        case "itemscope":
-            ValueProperty<String>(node: attribute).build(verbatim: "itemScope")
-        case "itemtype":
-            ValueProperty<String>(node: attribute).build(verbatim: "itemType")
-        case "kind":
-            TypeProperty<Kinds>(node: attribute).build()
-        case "label":
-            ValueProperty<String>(node: attribute).build()
-        case "lang":
-            TypeProperty<Language>(node: attribute).build(verbatim: "language")
-        case "list":
-            ValueProperty<String>(node: attribute).build()
-        case "loop":
-            EmptyProperty(node: attribute).build()
-        case "low":
-            ValueProperty<Float>(node: attribute).build()
-        case "max":
-
-            if let parent = attribute.parent {
-                
-                switch parent.localName {
-                case "progress", "meter":
-                    ValueProperty<Float>(node: attribute).build(verbatim: "maximum")
-                default:
-                    ValueProperty<String>(node: attribute).build(verbatim: "maximum")
-                }
-            }
-            
-        case "media":
-            ValueProperty<String>(node: attribute).build()
-        case "method":
-            TypeProperty<Method>(node: attribute).build()
-        case "min":
-            ValueProperty<String>(node: attribute).build(verbatim: "minimum")
-        case "multiple":
-            EmptyProperty(node: attribute).build()
-        case "muted":
-            EmptyProperty(node: attribute).build()
-        case "name":
-            
-            if let parent = attribute.parent {
-                
-                switch parent.localName {
-                case "meta":
-                    TypeProperty<Names>(node: attribute).build()
-                default:
-                    ValueProperty<String>(node: attribute).build()
-                }
-            }
-            
-        case "nonce":
-            ValueProperty<String>(node: attribute).build()
-        case "novalidate":
-            EmptyProperty(node: attribute).build()
-        case "open":
-            ValueProperty<Bool>(node: attribute).build(verbatim: "isOpen")
-        case "optimum":
-            ValueProperty<Float>(node: attribute).build()
-        case "pattern":
-            ValueProperty<String>(node: attribute).build()
-        case "part":
-            ValueProperty<String>(node: attribute).build()
-        case "ping":
-            ValueProperty<String>(node: attribute).build()
-        case "placeholder":
-            ValueProperty<String>(node: attribute).build()
-        case "poster":
-            ValueProperty<String>(node: attribute).build()
-        case "preload":
-            TypeProperty<Preload>(node: attribute).build()
-        case "readonly":
-            EmptyProperty(node: attribute).build()
-        case "referrerpolicy":
-            TypeProperty<Policy>(node: attribute).build(verbatim: "referrerPolicy")
-        case "rel":
-            TypeProperty<Relation>(node: attribute).build(verbatim: "relationship")
-        case "required":
-            EmptyProperty(node: attribute).build()
-        case "reversed":
-            EmptyProperty(node: attribute).build()
-        case "role":
-            TypeProperty<Roles>(node: attribute).build()
-        case "rows":
-            ValueProperty<String>(node: attribute).build()
-        case "rowspan":
-            ValueProperty<Int>(node: attribute).build(verbatim: "rowSpan")
-        case "sandbox":
-            EmptyProperty(node: attribute).build()
-        case "scope":
-            ValueProperty<String>(node: attribute).build()
-        case "shape":
-            TypeProperty<Shape>(node: attribute).build()
-        case "size":
-            ValueProperty<String>(node: attribute).build()
-        case "sizes":
-            ValueProperty<Int>(node: attribute).build()
-        case "slot":
-            ValueProperty<String>(node: attribute).build()
-        case "span":
-            ValueProperty<Int>(node: attribute).build()
-        case "spellcheck":
-            ValueProperty<Bool>(node: attribute).build(verbatim: "hasSpellCheck")
-        case "src":
-            ValueProperty<String>(node: attribute).build(verbatim: "source")
-        case "start":
-            ValueProperty<Int>(node: attribute).build()
-        case "step":
-            ValueProperty<Int>(node: attribute).build()
-        case "style":
-            ValueProperty<String>(node: attribute).build()
-        case "tabindex":
-            ValueProperty<Int>(node: attribute).build(verbatim: "tabIndex")
-        case "target":
-            TypeProperty<Target>(node: attribute).build()
-        case "title":
-            ValueProperty<String>(node: attribute).build()
-        case "translate":
-            TypeProperty<Decision>(node: attribute).build()
-        case "type":
-
-            if let parent = attribute.parent {
-                
-                switch parent.localName {
-                case "input":
-                    TypeProperty<Inputs>(node: attribute).build()
-                case "button":
-                    TypeProperty<Buttons>(node: attribute).build()
-                case "link", "script", "audio":
-                    TypeProperty<Medias>(node: attribute).build()
-                default:
-                    ValueProperty<String>(node: attribute).build()
-                }
-            }
-            
-        case "value":
-            ValueProperty<String>(node: attribute).build()
-        case "width":
-            ValueProperty<Int>(node: attribute).build()
-        case "wrap":
-            TypeProperty<Wrapping>(node: attribute).build()
-        case "property":
-            TypeProperty<Graphs>(node: attribute).build()
-        case "charset":
-            TypeProperty<Charset>(node: attribute).build()
-        case "http-equiv":
-            TypeProperty<Equivalent>(node: attribute).build()
-        case "selected":
-            EmptyProperty(node: attribute).build()
-        case "maxlength":
-            ValueProperty<String>(node: attribute).build(verbatim: "maximum")
-        case "minlength":
-            ValueProperty<String>(node: attribute).build(verbatim: "minimum")
-        case "d":
-            ValueProperty<String>(node: attribute).build(verbatim: "draw")
-        case "fill":
-            ValueProperty<String>(node: attribute).build()
-        case "fill-opacity":
-            ValueProperty<Double>(node: attribute).build(verbatim: "fillOpacity")
-        case "stroke":
-            ValueProperty<String>(node: attribute).build()
-        case "stroke-width":
-            ValueProperty<Int>(node: attribute).build(verbatim: "strokeWidth")
-        case "stroke-opacity":
-            ValueProperty<Double>(node: attribute).build(verbatim: "strokeOpacity")
-        case "stroke-linecap":
-            TypeProperty<Linecap>(node: attribute).build(verbatim: "strokeLineCap")
-        case "stroke-linejoin":
-            TypeProperty<Linejoin>(node: attribute).build(verbatim: "strokeLineJoin")
-        case "r":
-            ValueProperty<Int>(node: attribute).build(verbatim: "radius")
-        case "viewbox":
-            ValueProperty<String>(node: attribute).build(verbatim: "viewBox")
-        case "onafterprint":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onbeforeprint":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onbeforeunload":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onhashchange":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onlanguagechange":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onmessage":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onmessageerror":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onoffline":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "ononline":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onpagehide":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onpageshow":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onpopstate":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onrejectionhandled":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onstorage":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onunhandledrejection":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onunload":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onerror":
-            EventProperty<Events.Window>(node: attribute).build()
-        case "onblur":
-            EventProperty<Events.Focus>(node: attribute).build()
-        case "onfocus":
-            EventProperty<Events.Focus>(node: attribute).build()
-        case "onpointercancel":
-            EventProperty<Events.Pointer>(node: attribute).build()
-        case "onpointerdown":
-            EventProperty<Events.Pointer>(node: attribute).build()
-        case "onpointerenter":
-            EventProperty<Events.Pointer>(node: attribute).build()
-        case "onpointerleave":
-            EventProperty<Events.Pointer>(node: attribute).build()
-        case "onpointermove":
-            EventProperty<Events.Pointer>(node: attribute).build()
-        case "onpointerout":
-            EventProperty<Events.Pointer>(node: attribute).build()
-        case "onpointerover":
-            EventProperty<Events.Pointer>(node: attribute).build()
-        case "onpointerup":
-            EventProperty<Events.Pointer>(node: attribute).build()
-        case "onlostpointercapture":
-            EventProperty<Events.Pointer>(node: attribute).build()
-        case "onclick":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "oncontextmenu":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "ondblclick":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "onmousedown":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "onmouseenter":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "onmouseleave":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "onmousemove":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "onmouseout":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "onmouseover":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "onmouseup":
-            EventProperty<Events.Mouse>(node: attribute).build()
-        case "onwheel":
-            EventProperty<Events.Wheel>(node: attribute).build()
-        case "onbeforeinput":
-            EventProperty<Events.Input>(node: attribute).build()
-        case "oninput":
-            EventProperty<Events.Input>(node: attribute).build()
-        case "onselect":
-            EventProperty<Events.Input>(node: attribute).build()
-        case "onkeydown":
-            EventProperty<Events.Keyboard>(node: attribute).build()
-        case "onkeyup":
-            EventProperty<Events.Keyboard>(node: attribute).build()
-        case "ondrag":
-            EventProperty<Events.Drag>(node: attribute).build()
-        case "ondragend":
-            EventProperty<Events.Drag>(node: attribute).build()
-        case "ondragenter":
-            EventProperty<Events.Drag>(node: attribute).build()
-        case "ondragleave":
-            EventProperty<Events.Drag>(node: attribute).build()
-        case "ondragover":
-            EventProperty<Events.Drag>(node: attribute).build()
-        case "ondragstart":
-            EventProperty<Events.Drag>(node: attribute).build()
-        case "ondrop":
-            EventProperty<Events.Drag>(node: attribute).build()
-        case "oncopy":
-            EventProperty<Events.Clipboard>(node: attribute).build()
-        case "oncut":
-            EventProperty<Events.Clipboard>(node: attribute).build()
-        case "onpaste":
-            EventProperty<Events.Clipboard>(node: attribute).build()
-        case "onselectionchange":
-            EventProperty<Events.Selection>(node: attribute).build()
-        case "onselectstart":
-            EventProperty<Events.Selection>(node: attribute).build()
-        case "onabort":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "oncanplay":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "oncanplaythrough":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "ondurationchange":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onemptied":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onended":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onplay":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onplaying":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onpause":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onratechange":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onseeked":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onseeking":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onstalled":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onsuspend":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "ontimeupdate":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onvolumechange":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onwaiting":
-            EventProperty<Events.Media>(node: attribute).build()
-        case "onreset":
-            EventProperty<Events.Form>(node: attribute).build()
-        case "onsubmit":
-            EventProperty<Events.Form>(node: attribute).build()
-        case "ontoggle":
-            EventProperty<Events.Detail>(node: attribute).build()
-        case "aria-activedescendant":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "activeDescendant")
-        case "aria-atomic":
-            ValueProperty<Bool>(node: attribute, kind: .aria).build(verbatim: "atomic")
-        case "aria-autocomplete":
-            TypeProperty<Accessibility.Complete>(node: attribute, kind: .aria).build(verbatim: "autoComplete")
-        case "aria-busy":
-            ValueProperty<Bool>(node: attribute, kind: .aria).build(verbatim: "busy")
-        case "aria-checked":
-            TypeProperty<Accessibility.Check>(node: attribute, kind: .aria).build(verbatim: "checked")
-        case "aria-colcount":
-            ValueProperty<Int>(node: attribute, kind: .aria).build(verbatim: "columnCount")
-        case "aria-colindex":
-            ValueProperty<Int>(node: attribute, kind: .aria).build(verbatim: "columnIndex")
-        case "aria-colspan":
-            ValueProperty<Int>(node: attribute, kind: .aria).build(verbatim: "columnSpan")
-        case "aria-controls":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "controls")
-        case "aria-current":
-            TypeProperty<Accessibility.Current>(node: attribute, kind: .aria).build(verbatim: "current")
-        case "aria-describedby":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "describedBy")
-        case "aria-details":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "details")
-        case "aria-disabled":
-            ValueProperty<Bool>(node: attribute, kind: .aria).build(verbatim: "disabled")
-        case "aria-errormessage":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "errorMessage")
-        case "aria-expanded":
-            ValueProperty<Bool>(node: attribute, kind: .aria).build(verbatim: "expanded")
-        case "aria-flowto":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "flowTo")
-        case "aria-haspopup":
-            TypeProperty<Accessibility.Popup>(node: attribute, kind: .aria).build(verbatim: "hasPopup")
-        case "aria-hidden":
-            ValueProperty<Bool>(node: attribute).build(verbatim: "hidden")
-        case "aria-invalid":
-            TypeProperty<Accessibility.Invalid>(node: attribute, kind: .aria).build(verbatim: "invalid")
-        case "aria-keyshortcuts":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "keyShortcuts")
-        case "aria-label":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "label")
-        case "aria-labeledby":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "labeledBy")
-        case "aria-level":
-            ValueProperty<Int>(node: attribute, kind: .aria).build(verbatim: "level")
-        case "aria-live":
-            TypeProperty<Accessibility.Live>(node: attribute, kind: .aria).build(verbatim: "live")
-        case "aria-modal":
-            ValueProperty<Bool>(node: attribute, kind: .aria).build(verbatim: "modal")
-        case "aria-multiline":
-            ValueProperty<Bool>(node: attribute, kind: .aria).build(verbatim: "multiline")
-        case "aria-multiselectable":
-            ValueProperty<Bool>(node: attribute, kind: .aria).build(verbatim: "multiselectable")
-        case "aria-orientation":
-            TypeProperty<Accessibility.Orientation>(node: attribute, kind: .aria).build(verbatim: "orientation")
-        case "aria-owns":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "owns")
-        case "aria-placeholder":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "placeholder")
-        case "aria-posinset":
-            ValueProperty<Int>(node: attribute, kind: .aria).build(verbatim: "positionIndex")
-        case "aria-pressed":
-            TypeProperty<Accessibility.Pressed>(node: attribute, kind: .aria).build(verbatim: "pressed")
-        case "aria-readonly":
-            ValueProperty<Bool>(node: attribute, kind: .aria).build(verbatim: "readonly")
-        case "aria-relevant":
-            TypeProperty<Accessibility.Relevant>(node: attribute, kind: .aria).build(verbatim: "relevant")
-        case "aria-required":
-            ValueProperty<Bool>(node: attribute, kind: .aria).build(verbatim: "required")
-        case "aria-roledescription":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "roleDescription")
-        case "aria-rowcount":
-            ValueProperty<Int>(node: attribute, kind: .aria).build(verbatim: "rowCount")
-        case "aria-rowindex":
-            ValueProperty<Int>(node: attribute, kind: .aria).build(verbatim: "rowIndex")
-        case "aria-rowspan":
-            ValueProperty<Int>(node: attribute, kind: .aria).build(verbatim: "rowSpan")
-        case "aria-selected":
-            TypeProperty<Accessibility.Selected>(node: attribute, kind: .aria).build(verbatim: "selected")
-        case "aria-setsize":
-            ValueProperty<Int>(node: attribute, kind: .aria).build(verbatim: "setSize")
-        case "aria-sort":
-            TypeProperty<Accessibility.Sort>(node: attribute, kind: .aria).build(verbatim: "sort")
-        case "aria-valuemax":
-            ValueProperty<Float>(node: attribute, kind: .aria).build(verbatim: "valueMaximum")
-        case "aria-valuemin":
-            ValueProperty<Float>(node: attribute, kind: .aria).build(verbatim: "valueMinimum")
-        case "aria-valuenow":
-            ValueProperty<Float>(node: attribute, kind: .aria).build(verbatim: "valueNow")
-        case "aria-valuetext":
-            ValueProperty<String>(node: attribute, kind: .aria).build(verbatim: "valueText")
-        default:
-            CustomProperty(node: attribute).build()
-        }
-    }
-    
-    @StringBuilder private func decode(element: XMLNode, indent: Int? = nil) -> String {
-        
-        switch element.kind {
-        case .text:
-            
-            TextElement(node: element).build(preindent: indent)
-            
-        case .comment:
-            
-            CommentElement(node: element).build(preindent: indent)
-            
-        default:
-            
-            if let element = element as? XMLElement {
-             
-                switch element.localName {
-                case "html":
-                    ContentElement(element: element).build(preindent: indent)
-                case "head":
-                    ContentElement(element: element).build(verbatim: "Head", preindent: indent)
-                case "body":
-                    ContentElement(element: element).build(preindent: indent)
-                case "nav":
-                    ContentElement(element: element).build(verbatim: "Navigation", preindent: indent)
-                case "link":
-                    EmptyElement(element: element).build(preindent: indent)
-                case "aside":
-                    ContentElement(element: element).build(preindent: indent)
-                case "section":
-                    ContentElement(element: element).build(preindent: indent)
-                case "h1":
-                    ContentElement(element: element).build(verbatim: "Heading1", preindent: indent)
-                case "h2":
-                    ContentElement(element: element).build(verbatim: "Heading2", preindent: indent)
-                case "h3":
-                    ContentElement(element: element).build(verbatim: "Heading3", preindent: indent)
-                case "h4":
-                    ContentElement(element: element).build(verbatim: "Heading4", preindent: indent)
-                case "h5":
-                    ContentElement(element: element).build(verbatim: "Heading5", preindent: indent)
-                case "h6":
-                    ContentElement(element: element).build(verbatim: "Heading6", preindent: indent)
-                case "hgroup":
-                    ContentElement(element: element).build(verbatim: "HeadingGroup", preindent: indent)
-                case "header":
-                    ContentElement(element: element).build(preindent: indent)
-                case "footer":
-                    ContentElement(element: element).build(preindent: indent)
-                case "address":
-                    ContentElement(element: element).build(preindent: indent)
-                case "p":
-                    ContentElement(element: element).build(verbatim: "Paragraph", preindent: indent)
-                case "hr":
-                    EmptyElement(element: element).build(verbatim: "HorizontalRule", preindent: indent)
-                case "pre":
-                    ContentElement(element: element).build(verbatim: "PreformattedText", preindent: indent)
-                case "blockquote":
-                    ContentElement(element: element).build(preindent: indent)
-                case "ol":
-                    ContentElement(element: element).build(verbatim: "OrderedList", preindent: indent)
-                case "ul":
-                    ContentElement(element: element).build(verbatim: "UnorderedList", preindent: indent)
-                case "dl":
-                    ContentElement(element: element).build(verbatim: "DescriptionList", preindent: indent)
-                case "figure":
-                    ContentElement(element: element).build(preindent: indent)
-                case "a":
-                    ContentElement(element: element).build(verbatim: "Anchor", preindent: indent)
-                case "em":
-                    ContentElement(element: element).build(verbatim: "Emphasize", preindent: indent)
-                case "small":
-                    ContentElement(element: element).build(preindent: indent)
-                case "s":
-                    ContentElement(element: element).build(verbatim: "StrikeThrough", preindent: indent)
-                case "main":
-                    ContentElement(element: element).build(preindent: indent)
-                case "div":
-                    ContentElement(element: element).build(verbatim: "Division", preindent: indent)
-                case "dfn":
-                    ContentElement(element: element).build(verbatim: "Definition", preindent: indent)
-                case "cite":
-                    ContentElement(element: element).build(preindent: indent)
-                case "q":
-                    ContentElement(element: element).build(verbatim: "ShortQuote", preindent: indent)
-                case "rt":
-                    ContentElement(element: element).build(verbatim: "RubyText", preindent: indent)
-                case "rp":
-                    ContentElement(element: element).build(verbatim: "RubyPronunciation", preindent: indent)
-                case "abbr":
-                    ContentElement(element: element).build(verbatim: "Abbreviation", preindent: indent)
-                case "data":
-                    ContentElement(element: element).build(preindent: indent)
-                case "time":
-                    ContentElement(element: element).build(preindent: indent)
-                case "code":
-                    ContentElement(element: element).build(preindent: indent)
-                case "v":
-                    ContentElement(element: element).build(verbatim: "Variable", preindent: indent)
-                case "samp":
-                    ContentElement(element: element).build(verbatim: "SampleOutput", preindent: indent)
-                case "kbd":
-                    ContentElement(element: element).build(verbatim: "KeyboardOutput", preindent: indent)
-                case "sub":
-                    ContentElement(element: element).build(verbatim: "Subscript", preindent: indent)
-                case "sup":
-                    ContentElement(element: element).build(verbatim: "Superscript", preindent: indent)
-                case "i":
-                    ContentElement(element: element).build(verbatim: "Italic", preindent: indent)
-                case "b":
-                    ContentElement(element: element).build(verbatim: "Bold", preindent: indent)
-                case "strong":
-                    ContentElement(element: element).build(verbatim: "Strong", preindent: indent)
-                case "u":
-                    ContentElement(element: element).build(verbatim: "SampleOutput", preindent: indent)
-                case "mark":
-                    ContentElement(element: element).build(preindent: indent)
-                case "bdi":
-                    ContentElement(element: element).build(preindent: indent)
-                case "bdo":
-                    EmptyElement(element: element).build(preindent: indent)
-                case "span":
-                    ContentElement(element: element).build(preindent: indent)
-                case "br":
-                    EmptyElement(element: element).build(verbatim: "LineBreak", preindent: indent)
-                case "wbr":
-                    EmptyElement(element: element).build(verbatim: "WordBreak", preindent: indent)
-                case "ins":
-                    ContentElement(element: element).build(verbatim: "InsertedText", preindent: indent)
-                case "del":
-                    ContentElement(element: element).build(verbatim: "DeletedText", preindent: indent)
-                case "img":
-                    EmptyElement(element: element).build(verbatim: "Image", preindent: indent)
-                case "embed":
-                    ContentElement(element: element).build(preindent: indent)
-                case "iframe":
-                    ContentElement(element: element).build(verbatim: "InlineFrame", preindent: indent)
-                case "param":
-                    EmptyElement(element: element).build(verbatim: "Parameter", preindent: indent)
-                case "dt":
-                    ContentElement(element: element).build(verbatim: "TermName", preindent: indent)
-                case "dd":
-                    ContentElement(element: element).build(verbatim: "TermDefinition", preindent: indent)
-                case "figcaption":
-                    ContentElement(element: element).build(verbatim: "FigureCaption", preindent: indent)
-                case "optgroup":
-                    ContentElement(element: element).build(verbatim: "OptionGroup", preindent: indent)
-                case "option":
-                    ContentElement(element: element).build(preindent: indent)
-                case "legend":
-                    ContentElement(element: element).build(preindent: indent)
-                case "summary":
-                    ContentElement(element: element).build(preindent: indent)
-                case "li":
-                    ContentElement(element: element).build(verbatim: "ListItem", preindent: indent)
-                case "colgroup":
-                    ContentElement(element: element).build(verbatim: "ColumnGroup", preindent: indent)
-                case "col":
-                    ContentElement(element: element).build(verbatim: "Column", preindent: indent)
-                case "tbody":
-                    ContentElement(element: element).build(verbatim: "TableBody", preindent: indent)
-                case "thead":
-                    ContentElement(element: element).build(verbatim: "TableHead", preindent: indent)
-                case "tfoot":
-                    ContentElement(element: element).build(verbatim: "TableFoot", preindent: indent)
-                case "tr":
-                    ContentElement(element: element).build(verbatim: "TableRow", preindent: indent)
-                case "td":
-                    ContentElement(element: element).build(verbatim: "DataCell", preindent: indent)
-                case "th":
-                    ContentElement(element: element).build(verbatim: "HeaderCell", preindent: indent)
-                case "textarea":
-                    ContentElement(element: element).build(verbatim: "TextArea", preindent: indent)
-                case "input":
-                    EmptyElement(element: element).build(preindent: indent)
-                case "video":
-                    ContentElement(element: element).build(preindent: indent)
-                case "audio":
-                    ContentElement(element: element).build(preindent: indent)
-                case "map":
-                    ContentElement(element: element).build(preindent: indent)
-                case "area":
-                    ContentElement(element: element).build(preindent: indent)
-                case "form":
-                    ContentElement(element: element).build(preindent: indent)
-                case "datalist":
-                    ContentElement(element: element).build(preindent: indent)
-                case "output":
-                    ContentElement(element: element).build(preindent: indent)
-                case "meter":
-                    ContentElement(element: element).build(preindent: indent)
-                case "details":
-                    ContentElement(element: element).build(preindent: indent)
-                case "dialog":
-                    ContentElement(element: element).build(preindent: indent)
-                case "script":
-                    ContentElement(element: element).build(preindent: indent)
-                case "noscript":
-                    ContentElement(element: element).build(preindent: indent)
-                case "template":
-                    ContentElement(element: element).build(preindent: indent)
-                case "canvas":
-                    ContentElement(element: element).build(preindent: indent)
-                case "table":
-                    ContentElement(element: element).build(preindent: indent)
-                case "fieldset":
-                    ContentElement(element: element).build(preindent: indent)
-                case "button":
-                    ContentElement(element: element).build(preindent: indent)
-                case "select":
-                    ContentElement(element: element).build(preindent: indent)
-                case "label":
-                    ContentElement(element: element).build(preindent: indent)
-                case "title":
-                    ContentElement(element: element).build(preindent: indent)
-                case "base":
-                    EmptyElement(element: element).build(preindent: indent)
-                case "meta":
-                    EmptyElement(element: element).build(preindent: indent)
-                case "style":
-                    ContentElement(element: element).build(preindent: indent)
-                case "source":
-                    EmptyElement(element: element).build(preindent: indent)
-                case "track":
-                    EmptyElement(element: element).build(preindent: indent)
-                case "article":
-                    ContentElement(element: element).build(preindent: indent)
-                case "progress":
-                    ContentElement(element: element).build(preindent: indent)
-                case "circle":
-                    ContentElement(element: element).build(preindent: indent)
-                case "rect":
-                    ContentElement(element: element).build(verbatim: "Rectangle", preindent: indent)
-                case "ellipse":
-                    ContentElement(element: element).build(preindent: indent)
-                case "line":
-                    ContentElement(element: element).build(preindent: indent)
-                case "polygon":
-                    ContentElement(element: element).build(preindent: indent)
-                case "path":
-                    ContentElement(element: element).build(preindent: indent)
-                case "use":
-                    ContentElement(element: element).build(preindent: indent)
-                case "g":
-                    ContentElement(element: element).build(verbatim: "Group", preindent: indent)
-                default:
-                    "element is not listed. contact the author"
-                }
-            }
-        }
-    }
-}
-
-@available(macOS 11.0, *)
-extension Converter {
-    
-    private struct CommentElement {
-        
-        private var comment: String? {
-            
-            guard let comment = node.stringValue else {
-                return nil
-            }
-            
-            return comment
-        }
-        
-        private let node: XMLNode
-        
-        internal init(node: XMLNode) {
-            self.node = node
-        }
-        
-        @StringBuilder internal func build(preindent: Int? = nil) -> String {
-            
-            let indent = String(repeating: "\t", count: (node.level - 1) + (preindent ?? 0))
-            
-            if let comment = comment
-            {
-                "\(indent)Comment(\"\(comment)\")\n"
-            }
-        }
-    }
-
-    private struct TextElement {
-        
-        private var text: String? {
-            
-            guard let text = node.stringValue else {
-                return nil
-            }
-            
-            return text
-        }
-        
-        private let node: XMLNode
-        
-        internal init(node: XMLNode) {
-            self.node = node
-        }
-        
-        @StringBuilder internal func build(preindent: Int? = nil) -> String {
-            
-            let indent = String(repeating: "\t", count: (node.level - 1) + (preindent ?? 0))
-            
-            if let text = text {
-                
-                if node.parent?.localName == "pre" {
-                    
-                    "\(indent)\"\"\"\n\(text)\"\"\"\n"
-                    
-                } else {
-                    
-                    "\(indent)\"\(text.trimmingCharacters(in: .whitespacesAndNewlines))\"\n"
-                }
-            }
-        }
-    }
-
-    private struct ContentElement {
-
-        private var name: String? {
-            
-            guard let name = element.name else {
-                return nil
-            }
-        
-            return name.capitalized
-        }
-        
-        private var attributes: [String]? {
-            
-            guard let attributes = element.attributes else {
-                return nil
-            }
-            
-            return attributes.map { attribute in
-                return Converter.default.decode(attribute: attribute)
-            }
-        }
-        
-        private var content: [String]? {
-            
-            guard let children = element.children else {
-                return nil
-            }
-            
-            return children.map { child in
-                return Converter.default.decode(element: child, indent: 2)
-            }
-        }
-        
-        private var level: Int {
-            return element.level
-        }
-        
-        private let element: XMLElement
-        
-        internal init(element: XMLElement) {
-            self.element = element
-        }
-        
-        @StringBuilder internal func build(preindent: Int? = nil) -> String {
-            
-            let indent = String(repeating: "\t", count: (level - 1) + (preindent ?? 0))
-            
-            if let name = name {
-                
-                "\(indent)\(name) {\n"
-
-                if let content = content {
-                    content.joined()
-                }
-                
-                "\(indent)}\n"
-                
-                if let attributes = attributes {
-                    "\(indent)\(attributes.joined(separator: "\(indent)"))"
-                }
-            }
-        }
-        
-        @StringBuilder internal func build(verbatim: String? = nil, preindent: Int? = nil) -> String {
-            
-            let indent = String(repeating: "\t", count: (level - 1) + (preindent ?? 0))
-            
-            if let verbatim = verbatim {
-                
-                "\(indent)\(verbatim) {\n"
-
-                if let content = content {
-                    content.joined()
-                }
-                
-                "\(indent)}\n"
-                
-                if let attributes = attributes {
-                    "\(indent)\(attributes.joined(separator: "\(indent)"))"
-                }
-            }
-        }
-    }
-
-    private struct EmptyElement {
-
-        private var name: String? {
-            
-            guard let name = element.name else {
-                return nil
-            }
-        
-            return name.capitalized
-        }
-        
-        private var attributes: [String]? {
-            
-            guard let attributes = element.attributes else {
-                return nil
-            }
-            
-            return attributes.map { attribute in
-                return Converter.default.decode(attribute: attribute)
-            }
-        }
-        
-        private var level: Int {
-            return element.level
-        }
-        
-        private let element: XMLElement
-        
-        internal init(element: XMLElement) {
-            self.element = element
-        }
-        
-        @StringBuilder internal func build(preindent: Int? = nil) -> String {
-
-            let indent = String(repeating: "\t", count: (level - 1) + (preindent ?? 0))
-
-            if let name = name {
-                
-                "\(indent)\(name)()\n"
-                
-                if let attributes = attributes {
-                    "\(indent)\t\(attributes.joined(separator: "\t\(indent)"))"
-                }
-            }
-        }
-        
-        @StringBuilder internal func build(verbatim: String? = nil, preindent: Int? = nil) -> String {
-
-            let indent = String(repeating: "\t", count: (level - 1) + (preindent ?? 0))
-
-            if let verbatim = verbatim {
-        
-                "\(indent)\(verbatim)()\n"
-                
-                if let attributes = attributes {
-                    "\(indent)\t\(attributes.joined(separator: "\t\(indent)"))"
-                }
-                
-            }
-        }
-    }
-
-    private struct PageLayout<T: RawRepresentable> {
-        
-        private var name: String
-        
-        private var content: String {
-            return Converter.default.decode(element: root, indent: 2)
-        }
-        
-        private var type: String {
-            
-            if let name = doctype.name, let publicId = doctype.publicID, let systemId = doctype.systemID {
-                
-                if let type = T(rawValue: "\(name) PUBLIC \"\(publicId)\" \"\(systemId)\"" as! T.RawValue) {
-                    return ".\(type)"
-                }
-            }
-            
-            return ".html5"
-        }
-        
-        private var doctype: XMLDTD
-        
-        private var root: XMLElement
-        
-        internal init(name: String, doctype: XMLDTD, root: XMLElement) {
-            self.name = name.capitalized
-            self.doctype = doctype
-            self.root = root
-        }
-        
-        internal func build() -> String {
-            
-            """
-            import HTMLKit
-            
-            struct \(name)Page: Page {
-            
-                public var body: AnyContent {
-                    Document(type: \(type))
-            \(content)
-                }
-            }
-            """
-        }
-    }
-
-    private struct ViewLayout {
-        
-        private var name: String
-        
-        private var content: String {
-            return Converter.default.decode(element: root, indent: 2)
-        }
-        
-        private var root: XMLElement
-        
-        internal init(name: String, root: XMLElement) {
-            self.name = name.capitalized
-            self.root = root
-        }
-        
-        internal func build() -> String {
-            
-            """
-            import HTMLKit
-            
-            struct \(name)View: View {
-            
-                @TemplateValue(String.self) var context
-            
-                public var body: AnyContent {
-            \(content)
-                }
-            }
-            """
-        }
-    }
-
-    private struct ValueProperty<T: InitRepresentable> {
-        
-        internal enum PropertyKind {
-            case normal
-            case aria
-        }
-        
-        private var kind: PropertyKind
-        
-        private var name: String? {
-            
-            guard let name = node.name else {
-                return nil
-            }
-            
-            return name
-        }
-        
-        private var value: T? {
-            
-            guard let value = node.stringValue else {
-                return nil
-            }
-            
-            return T(value: value)
-        }
-        
-        private let node: XMLNode
-        
-        internal init(node: XMLNode, kind: PropertyKind = .normal) {
-            self.node = node
-            self.kind = kind
-        }
-        
-        @StringBuilder internal func build() -> String {
-
-            switch kind {
-            case .normal:
-                
-                if let name = self.name, let value = self.value {
-                    
-                    switch value {
-                    case is Float, is Int, is Double, is Bool:
-                        
-                        ".\(name)(\(value))\n"
-                        
-                    default:
-                        
-                        ".\(name)(\"\(value)\")\n"
-                    }
-                    
-                } else if let name = name {
-                    
-                    ".\(name)()\n"
-                }
-                
-            case .aria:
-                
-                if let name = self.name, let value = self.value {
-                    
-                    switch value {
-                    case is Float, is Int, is Double, is Bool:
-                        ".aria(\(name): \(value))\n"
-                        
-                    default:
-                        ".aria(\(name): \"\(value)\")\n"
-                    }
-                }
-            }
-        }
-        
-        @StringBuilder internal func build(verbatim: String? = nil) -> String {
-
-            switch kind {
-            case .normal:
-                
-                if let verbatim = verbatim, let value = value {
-                    
-                    switch value {
-                    case is Float, is Int, is Double, is Bool:
-                        
-                        ".\(verbatim)(\(value))\n"
-                        
-                    default:
-                        
-                        ".\(verbatim)(\"\(value)\")\n"
-                    }
-                    
-                } else if let verbatim = verbatim {
-                    
-                    ".\(verbatim)()\n"
-                }
-                
-            case .aria:
-                
-                if let verbatim = verbatim, let value = value {
-                    
-                    switch value {
-                    case is Float, is Int, is Double, is Bool:
-                        ".aria(\(verbatim): \(value))\n"
-                        
-                    default:
-                        ".aria(\(verbatim): \"\(value)\")\n"
-                    }
-                }
-            }
-        }
-    }
-
-    private struct EmptyProperty {
-        
-        private var name: String? {
-            
-            guard let name = node.name else {
-                return nil
-            }
-            
-            return name
-        }
-        
-        private let node: XMLNode
-        
-        internal init(node: XMLNode) {
-            self.node = node
-        }
-        
-        @StringBuilder internal func build() -> String {
-
-            if let name = name {
-                ".\(name)()\n"
-            }
-        }
-        
-        @StringBuilder internal func build(verbatim: String? = nil) -> String {
-
-            if let verbatim = verbatim {
-                ".\(verbatim)()\n"
-            }
-        }
-    }
-
-    private struct TypeProperty<T: RawRepresentable>{
-        
-        internal enum PropertyKind {
-            case normal
-            case aria
-        }
-        
-        private var kind: PropertyKind
-        
-        private var name: String? {
-            
-            guard let name = node.name else {
-                return nil
-            }
-            
-            return name
-        }
-        
-        private var value: T? {
-
-            guard let value = node.stringValue  else {
-                return nil
-            }
-            
-            return T(rawValue: value.lowercased() as! T.RawValue)
-        }
-        
-        private let node: XMLNode
-        
-        internal init(node: XMLNode, kind: PropertyKind = .normal) {
-            self.node = node
-            self.kind = kind
-        }
-        
-        @StringBuilder internal func build() -> String {
-
-            switch kind {
-            case .normal:
-                
-                if let name = name, let value = value {
-                    
-                    ".\(name)(.\(value))\n"
-                    
-                } else if let name = name{
-                    
-                    ".\(name)()\n"
-                }
-                
-            case .aria:
-                
-                if let name = name, let value = value {
-                    ".aria(\(name): .\(value))\n"
-                }
-            }
-        }
-        
-        @StringBuilder internal func build(verbatim: String? = nil) -> String {
-
-            switch kind {
-            case .normal:
-                
-                if let verbatim = verbatim, let value = value {
-                    
-                    ".\(verbatim)(.\(value))\n"
-                    
-                } else if let verbatim = verbatim {
-                    
-                    ".\(verbatim)()\n"
-                }
-                
-            case .aria:
-                
-                if let verbatim = verbatim, let value = value {
-                    ".aria(\(verbatim): .\(value))\n"
-                }
-            }
-        }
-    }
-
-    private struct CustomProperty {
-        
-        private var name: String? {
-            
-            guard let name = node.name else {
-                return nil
-            }
-            
-            return name
-        }
-        
-        private var value: String? {
-            
-            guard let value = node.stringValue else {
-                return nil
-            }
-            
-            return value
-        }
-        
-        private let node: XMLNode
-        
-        internal init(node: XMLNode) {
-            self.node = node
-        }
-        
-        @StringBuilder internal func build() -> String {
-
-            if let name = name {
-                ".custom(key: \"\(name)\", value: \"\(value ?? "")\")\n"
-            }
-        }
-    }
-    
-    private struct EventProperty<T: RawRepresentable> {
-        
-        private var name: T? {
-
-            guard let name = node.localName  else {
-                return nil
-            }
-            
-            return T(rawValue: name.lowercased() as! T.RawValue)
-        }
-        
-        private var value: String? {
-            
-            guard let value = node.stringValue else {
-                return nil
-            }
-            
-            return value
-        }
-        
-        private let node: XMLNode
-        
-        internal init(node: XMLNode) {
-            self.node = node
-        }
-        
-        @StringBuilder internal func build() -> String {
-
-            if let name = name {
-                ".on(event: .\(name), \"\(value ?? "")\")\n"
-            }
-        }
-    }
-}
-
-public protocol InitRepresentable {
-    
-    init?(value: String)
-}
-
-extension String: InitRepresentable {
-    
-    public init?(value: String) {
-        self.init(value)
-    }
-}
-
-extension Float: InitRepresentable {
-    
-    public init?(value: String) {
-        self.init(value)
-    }
-}
-
-extension Int: InitRepresentable {
-    
-    public init?(value: String) {
-        self.init(value)
-    }
-}
-
-extension Double: InitRepresentable {
-    
-    public init?(value: String) {
-        self.init(value)
-    }
-}
-
-extension Bool: InitRepresentable {
-    
-    public init?(value: String) {
-        self.init(value)
-    }
-}
diff --git a/Tests/HTMLKitTests/Conversion/articles/article.html b/Tests/ConverterTests/Conversion/articles/article.html
similarity index 100%
rename from Tests/HTMLKitTests/Conversion/articles/article.html
rename to Tests/ConverterTests/Conversion/articles/article.html
diff --git a/Tests/HTMLKitTests/Conversion/component.html b/Tests/ConverterTests/Conversion/component.html
similarity index 100%
rename from Tests/HTMLKitTests/Conversion/component.html
rename to Tests/ConverterTests/Conversion/component.html
diff --git a/Tests/HTMLKitTests/Conversion/index.html b/Tests/ConverterTests/Conversion/index.html
similarity index 100%
rename from Tests/HTMLKitTests/Conversion/index.html
rename to Tests/ConverterTests/Conversion/index.html
diff --git a/Tests/HTMLKitTests/ConversionTests.swift b/Tests/ConverterTests/ConversionTests.swift
similarity index 53%
rename from Tests/HTMLKitTests/ConversionTests.swift
rename to Tests/ConverterTests/ConversionTests.swift
index 98c48b02..c10e36fe 100644
--- a/Tests/HTMLKitTests/ConversionTests.swift
+++ b/Tests/ConverterTests/ConversionTests.swift
@@ -1,4 +1,4 @@
-import HTMLKit
+import Converter
 import XCTest
 
 final class ConversionTests: XCTestCase {
@@ -20,24 +20,7 @@ final class ConversionTests: XCTestCase {
             return XCTFail("No directory.")
         }
         
-        XCTAssertNoThrow(try Converter.default.convert(directory: directory, option: .print))
-#endif
-    }
-    
-    func testStringConversion() throws {
-        
-#if os(Linux)
-        throw XCTSkip("Requires macOS >= 11.0")
-#else
-        guard let directory = directory else {
-            return XCTFail("No directory.")
-        }
-        
-        guard let content = try? String(contentsOf: directory.appendingPathComponent("component.html")) else {
-            return XCTFail("No file.")
-        }
-        
-        XCTAssertNoThrow(try Converter.default.convert(html: content))
+        XCTAssertNoThrow(try Converter.default.convert(source: directory))
 #endif
     }
 }