diff --git a/Castor/Sources/Castor.swift b/Castor/Sources/Castor.swift deleted file mode 100644 index 1a0a45df..00000000 --- a/Castor/Sources/Castor.swift +++ /dev/null @@ -1 +0,0 @@ -// This file is just here as a foolproof/template since for Swift Packages a module source always have to have at least one Swift file diff --git a/Castor/Sources/CastorImpl+Public.swift b/Castor/Sources/CastorImpl+Public.swift new file mode 100644 index 00000000..bd4968f1 --- /dev/null +++ b/Castor/Sources/CastorImpl+Public.swift @@ -0,0 +1,7 @@ +import Domain + +extension CastorImpl: Castor { + public func parseDID(str: String) throws -> DID { + try DIDParser(didString: str).parse() + } +} diff --git a/Castor/Sources/CastorImpl.swift b/Castor/Sources/CastorImpl.swift new file mode 100644 index 00000000..a7e49acb --- /dev/null +++ b/Castor/Sources/CastorImpl.swift @@ -0,0 +1 @@ +public struct CastorImpl {} diff --git a/Castor/Sources/DIDParser.swift b/Castor/Sources/DIDParser.swift new file mode 100644 index 00000000..1bb5a2dd --- /dev/null +++ b/Castor/Sources/DIDParser.swift @@ -0,0 +1,56 @@ +import Antlr4 +import Domain +import Foundation + +struct DIDParser { + struct InvalidDIDStringError: Error {} + + let didString: String + + func parse() throws -> DID { + let inputStream = ANTLRInputStream(didString) + let lexer = DIDAbnfLexer(inputStream) + let tokenStream = CommonTokenStream(lexer) + + let parser = try DIDAbnfParser(tokenStream) + parser.setErrorHandler(BailErrorStrategy()) + let context = try parser.did() + + let listener = Listener() + try ParseTreeWalker().walk(listener, context) + + guard + let schema = listener.scheme, + let methodName = listener.methodName, + let methodId = listener.methodId + else { throw InvalidDIDStringError() } + + let did = DID( + schema: schema, + method: methodName, + methodId: methodId + ) + + return did + } +} + +fileprivate final class Listener: DIDAbnfBaseListener { + fileprivate var scheme: String? + fileprivate var methodName: String? + fileprivate var methodId: String? + + override func exitDid(_ ctx: DIDAbnfParser.DidContext) { + ctx.SCHEMA().map { scheme = $0.getText() } + } + + override func exitMethod_name(_ ctx: DIDAbnfParser.Method_nameContext) { + methodName = ctx.getText() + } + + override func exitMethod_specific_id( + _ ctx: DIDAbnfParser.Method_specific_idContext + ) { + methodId = ctx.getText() + } +} diff --git a/Castor/Tests/DIDParserTests.swift b/Castor/Tests/DIDParserTests.swift new file mode 100644 index 00000000..b10b49c0 --- /dev/null +++ b/Castor/Tests/DIDParserTests.swift @@ -0,0 +1,41 @@ +import XCTest +@testable import Castor + +final class DIDParserTests: XCTestCase { + + func testValidDIDs() throws { + let didExample1 = "did:aaaaaa:aa:aaa" + let didExample2 = "did:prism01:b2.-_%11:b4._-%11" + let didExample3 = "did:prism:b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k" + + let parsedDID1 = try DIDParser(didString: didExample1).parse() + let parsedDID2 = try DIDParser(didString: didExample2).parse() + let parsedDID3 = try DIDParser(didString: didExample3).parse() + + XCTAssertEqual(parsedDID1.schema, "did") + XCTAssertEqual(parsedDID1.method, "aaaaaa") + XCTAssertEqual(parsedDID1.methodId, "aa:aaa") + + XCTAssertEqual(parsedDID2.schema, "did") + XCTAssertEqual(parsedDID2.method, "prism01") + XCTAssertEqual(parsedDID2.methodId, "b2.-_%11:b4._-%11") + + XCTAssertEqual(parsedDID3.schema, "did") + XCTAssertEqual(parsedDID3.method, "prism") + XCTAssertEqual(parsedDID3.methodId, "b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k") + } + + func testInvalidDIDs() throws { + let didExample1 = "idi:aaaaaa:aa:aaa" + let didExample2 = "did:-prism-:aaaaa:aaaa" + let didExample3 = "did:prism:aaaaaaaaaaa::" + let didExample4 = "did::prism:aaaaaaaaaaa:aaaa" + let didExample5 = "did:prism::aaaaaaaaaaa:aaaa" + + XCTAssertThrowsError(try DIDParser(didString: didExample1).parse()) + XCTAssertThrowsError(try DIDParser(didString: didExample2).parse()) + XCTAssertThrowsError(try DIDParser(didString: didExample3).parse()) + XCTAssertThrowsError(try DIDParser(didString: didExample4).parse()) + XCTAssertThrowsError(try DIDParser(didString: didExample5).parse()) + } +} diff --git a/Domain/Sources/BBs/Castor.swift b/Domain/Sources/BBs/Castor.swift new file mode 100644 index 00000000..75fdac09 --- /dev/null +++ b/Domain/Sources/BBs/Castor.swift @@ -0,0 +1,3 @@ +public protocol Castor { + func parseDID(str: String) throws -> DID +}