<commit_before>import Foundation
import AEXML
import Stencil


private func template(named name: String) -> Template {
    return try! Template(URL: Bundle.main.url(forResource: name, withExtension: "stencil", subdirectory: "Stencils")!)
}


private let typeMap: [String: String] = [
    "string": "\(String.self)", // xs:string
    "boolean": "\(Bool.self)", // xs:boolean
    "int": "\(Int32.self)",
    "long": "\(Int64.self)",
    "dateTime": "\(Date.self)",
    "base64Binary": "\(Data.self)",
]

private let swiftKeywords: [String] = [
    "operator",
    "return",
]
private func swiftKeywordsAvoidedName(_ name: String) -> String {
    return swiftKeywords.contains(name) ? name + "_" : name
}


private func replaceTargetNameSpace(_ name: String, prefix: String) -> String {
    return name.replacingOccurrences(of: "tns:", with: prefix)
}


struct Core {
    static func main(out: URL, in files: [String]) throws {
        let preamble = try template(named: "Preamble").render()
        var wsdls: [WSDL] = []
        var types: [(prefix: String, type: XSDType)] = []

        // each file can be either WSDL or XSD file
        for f in files {
            if let wsdl = WSDL(path: f) {
                wsdls.append(wsdl)

                (wsdl.types?["schema"].all ?? []).forEach { s in
                    var options = AEXMLOptions()
                    options.parserSettings.shouldProcessNamespaces = true // ignore namespace
                    options.parserSettings.shouldReportNamespacePrefixes = false // ignore namespace
                    let xml = AEXMLDocument(root: s, options: options)
                    if let xsd = parseXSD(xml, prefix: wsdl.prefix) {
                        types.append(contentsOf: xsd)
                    }
                }

                continue
            }

            guard let wsdl = wsdls.last else {
                print("error: files.first should be WSDL xml file: \(f)")
                return
            }

            guard let xsd = parseXSD(f, prefix: wsdl.prefix) else {
                print("error: file is not WSDL nor XSD: \(f)")
                return
            }
            types.append(contentsOf: xsd)
        }

        guard !wsdls.isEmpty else {
            print("error: no WSDLs found in: \(files)")
            return
        }

        let extensions = types.map {$0.type.dictionariesForExpressibleByXMLProtocol(types.map {$0.type}, typeQualifier: [])}.joined()
        let expressibleByXMLExtensions: [String] = extensions.map {try! compact(template(named: "ExpressibleByXML").render(Context(dictionary: $0)))}
        
        try (preamble
            + types.map {compact($0.type.swift(types.map {$0.type}, prefix: $0.prefix))}.joined(separator: "\n")
            + "\n\n"
            + wsdls.map {$0.swift()}.joined()
            + expressibleByXMLExtensions.joined())
            .write(to: out, atomically: true, encoding: .utf8)
    }

    fileprivate static func parseXSD(_ path: String, prefix: String) -> [(prefix: String, type: XSDType)]? {
        var options = AEXMLOptions()
        options.parserSettings.shouldProcessNamespaces = true // ignore namespace
        options.parserSettings.shouldReportNamespacePrefixes = false // ignore namespace
        guard let xsd = try? AEXMLDocument(xml: Data(contentsOf: URL(fileURLWithPath: path)), options: options) else { return nil }
        return parseXSD(xsd, prefix: prefix)
    }

    fileprivate static func parseXSD(_ xsd: AEXMLDocument, prefix: String) -> [(prefix: String, type: XSDType)]? {
        // * top-level <complexType name="...">... use the name as type name
        // * child of element <complexType>... use the enclosing element name as type name
        guard xsd.root.name == "schema" else { return nil }
        let complexTypes: [AEXMLElement] = (xsd.root["complexType"].all ?? [])
            + ((xsd.root["element"].all ?? []).flatMap {$0["complexType"].all}.joined())
        let types = complexTypes
            .flatMap {XSDType.deserialize($0, prefix: prefix)}
            .map {(prefix, $0)}
        return types<commit_msg>order output as services, types, preamble and extensions for protocol conformances<commit_after>import Foundation
import AEXML
import Stencil


private func template(named name: String) -> Template {
    return try! Template(URL: Bundle.main.url(forResource: name, withExtension: "stencil", subdirectory: "Stencils")!)
}


private let typeMap: [String: String] = [
    "string": "\(String.self)", // xs:string
    "boolean": "\(Bool.self)", // xs:boolean
    "int": "\(Int32.self)",
    "long": "\(Int64.self)",
    "dateTime": "\(Date.self)",
    "base64Binary": "\(Data.self)",
]

private let swiftKeywords: [String] = [
    "operator",
    "return",
]
private func swiftKeywordsAvoidedName(_ name: String) -> String {
    return swiftKeywords.contains(name) ? name + "_" : name
}


private func replaceTargetNameSpace(_ name: String, prefix: String) -> String {
    return name.replacingOccurrences(of: "tns:", with: prefix)
}


struct Core {
    static func main(out: URL, in files: [String]) throws {
        let preamble = try template(named: "Preamble").render()
        var wsdls: [WSDL] = []
        var types: [(prefix: String, type: XSDType)] = []

        // each file can be either WSDL or XSD file
        for f in files {
            if let wsdl = WSDL(path: f) {
                wsdls.append(wsdl)

                (wsdl.types?["schema"].all ?? []).forEach { s in
                    var options = AEXMLOptions()
                    options.parserSettings.shouldProcessNamespaces = true // ignore namespace
                    options.parserSettings.shouldReportNamespacePrefixes = false // ignore namespace
                    let xml = AEXMLDocument(root: s, options: options)
                    if let xsd = parseXSD(xml, prefix: wsdl.prefix) {
                        types.append(contentsOf: xsd)
                    }
                }

                continue
            }

            guard let wsdl = wsdls.last else {
                print("error: files.first should be WSDL xml file: \(f)")
                return
            }

            guard let xsd = parseXSD(f, prefix: wsdl.prefix) else {
                print("error: file is not WSDL nor XSD: \(f)")
                return
            }
            types.append(contentsOf: xsd)
        }

        guard !wsdls.isEmpty else {
            print("error: no WSDLs found in: \(files)")
            return
        }

        let extensions = types.map {$0.type.dictionariesForExpressibleByXMLProtocol(types.map {$0.type}, typeQualifier: [])}.joined()
        let expressibleByXMLExtensions: [String] = extensions.map {try! compact(template(named: "ExpressibleByXML").render(Context(dictionary: $0)))}
        
        try (wsdls.map {$0.swift()}.joined()
            + types.map {compact($0.type.swift(types.map {$0.type}, prefix: $0.prefix))}.joined(separator: "\n")
            + "\n\n"
            + preamble
            + expressibleByXMLExtensions.joined())
            .write(to: out, atomically: true, encoding: .utf8)
    }

    fileprivate static func parseXSD(_ path: String, prefix: String) -> [(prefix: String, type: XSDType)]? {
        var options = AEXMLOptions()
        options.parserSettings.shouldProcessNamespaces = true // ignore namespace
        options.parserSettings.shouldReportNamespacePrefixes = false // ignore namespace
        guard let xsd = try? AEXMLDocument(xml: Data(contentsOf: URL(fileURLWithPath: path)), options: options) else { return nil }
        return parseXSD(xsd, prefix: prefix)
    }

    fileprivate static func parseXSD(_ xsd: AEXMLDocument, prefix: String) -> [(prefix: String, type: XSDType)]? {
        // * top-level <complexType name="...">... use the name as type name
        // * child of element <complexType>... use the enclosing element name as type name
        guard xsd.root.name == "schema" else { return nil }
        let complexTypes: [AEXMLElement] = (xsd.root["complexType"].all ?? [])
            + ((xsd.root["element"].all ?? []).flatMap {$0["complexType"].all}.joined())
        let types = complexTypes
            .flatMap {XSDType.deserialize($0, prefix: prefix)}
            .map {(prefix, $0)}
        return types
{'fraction_non_alphanumeric': 0.132255339688669, 'fraction_numerical': 0.004102811632677688, 'mean_word_length': 2.295427435387674, 'pattern_counts': {'":': 12, '<': 7, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 8}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5484518', 'n_tokens_mistral': 2468, 'n_tokens_neox': 2341, 'n_words': 639}