Skip to content

Commit 8717b19

Browse files
committed
Initial implementation of Swift Domain type with RFC compliance
- Implements unified Domain type supporting RFC 1035, RFC 1123, and RFC 5321 standards - Provides domain validation, subdomain operations, and parent/child relationships - Includes comprehensive test suite with 53 passing tests - Supports Codable, RawRepresentable, and CustomStringConvertible protocols - Clean API for domain name handling across different RFC requirements
1 parent e0e2116 commit 8717b19

File tree

7 files changed

+138
-255
lines changed

7 files changed

+138
-255
lines changed

Package.resolved

Lines changed: 13 additions & 49 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ extension Target.Dependency {
1212
}
1313

1414
extension Target.Dependency {
15-
static var rfc1035: Self { .product(name: "RFC 1035", package: "swift-web-standards") }
16-
static var rfc1123: Self { .product(name: "RFC 1123", package: "swift-web-standards") }
17-
static var rfc5321: Self { .product(name: "RFC 5321", package: "swift-web-standards") }
15+
static var rfc1035: Self { .product(name: "RFC_1035", package: "swift-rfc-1035") }
16+
static var rfc1123: Self { .product(name: "RFC_1123", package: "swift-rfc-1123") }
17+
static var rfc5321: Self { .product(name: "RFC_5321", package: "swift-rfc-5321") }
1818
}
1919

2020
let package = Package(
@@ -24,7 +24,9 @@ let package = Package(
2424
.library(name: .domain, targets: [.domain])
2525
],
2626
dependencies: [
27-
.package(url: "https://github.com/coenttb/swift-web-standards", branch: "main")
27+
.package(url: "https://github.com/swift-web-standards/swift-rfc-1035", from: "0.0.1"),
28+
.package(url: "https://github.com/swift-web-standards/swift-rfc-1123", from: "0.0.1"),
29+
.package(url: "https://github.com/swift-web-standards/swift-rfc-5321", from: "0.0.1")
2830
],
2931
targets: [
3032
.target(
@@ -38,7 +40,10 @@ let package = Package(
3840
.testTarget(
3941
name: .domain.tests,
4042
dependencies: [
41-
.domain
43+
.domain,
44+
.rfc1035,
45+
.rfc1123,
46+
.rfc5321
4247
]
4348
)
4449
],

README.md

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,9 @@
66

77
### The coenttb stack
88

9-
* [swift-css](https://www.github.com/coenttb/swift-css): A Swift DSL for type-safe CSS.
10-
* [swift-html](https://www.github.com/coenttb/swift-html): A Swift DSL for type-safe HTML & CSS, integrating [swift-css](https://www.github.com/coenttb/swift-css) and [pointfree-html](https://www.github.com/coenttb/pointfree-html).
11-
* [swift-web](https://www.github.com/coenttb/swift-web): Foundational tools for web development in Swift.
12-
* [coenttb-html](https://www.github.com/coenttb/coenttb-html): Builds on [swift-html](https://www.github.com/coenttb/swift-html), and adds functionality for HTML, Markdown, Email, and printing HTML to PDF.
13-
* [coenttb-web](https://www.github.com/coenttb/coenttb-web): Builds on [swift-web](https://www.github.com/coenttb/swift-web), and adds functionality for web development.
14-
* [coenttb-server](https://www.github.com/coenttb/coenttb-server): Build fast, modern, and safe servers that are a joy to write. `coenttb-server` builds on [coenttb-web](https://www.github.com/coenttb/coenttb-web), and adds functionality for server development.
15-
* [coenttb-vapor](https://www.github.com/coenttb/coenttb-server-vapor): `coenttb-server-vapor` builds on [coenttb-server](https://www.github.com/coenttb/coenttb-server), and adds functionality and integrations with Vapor and Fluent.
16-
* [coenttb-com-server](https://www.github.com/coenttb/coenttb-com-server): The backend server for coenttb.com, written entirely in Swift and powered by [coenttb-server-vapor](https://www.github.com/coenttb-server-vapor).
17-
18-
### PointFree foundations
19-
* [coenttb/pointfree-html](https://www.github.com/coenttb/pointfree-html): A Swift DSL for type-safe HTML, forked from [pointfreeco/swift-html](https://www.github.com/pointfreeco/swift-html) and updated to the version on [pointfreeco/pointfreeco](https://github.com/pointfreeco/pointfreeco).
20-
* [coenttb/pointfree-web](https://www.github.com/coenttb/pointfree-html): Foundational tools for web development in Swift, forked from [pointfreeco/swift-web](https://www.github.com/pointfreeco/swift-web).
21-
* [coenttb/pointfree-server](https://www.github.com/coenttb/pointfree-html): Foundational tools for server development in Swift, forked from [pointfreeco/swift-web](https://www.github.com/pointfreeco/swift-web).
9+
* [coenttb-web](https://www.github.com/coenttb/coenttb-web): Web development in Swift.
10+
* [coenttb-server](https://www.github.com/coenttb/coenttb-server): Server development in Swift.
11+
* [coenttb-com-server](https://www.github.com/coenttb/coenttb-com-server): Public source code repository for [coenttb.com](https://coenttb.com), a 100% Swift website built on coenttb-server and coenttb-web.
2212

2313
## Feedback is Much Appreciated!
2414

Tests/Domain Tests/Domain Tests.swift

Lines changed: 8 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -15,48 +15,12 @@ struct DomainTests {
1515
func testCreateFromString() throws {
1616
let domain = try Domain("example.com")
1717
#expect(domain.name == "example.com")
18-
#expect(domain.isStandardDomain)
19-
#expect(!domain.isAddressLiteral)
20-
#expect(domain.tld == "com")
21-
#expect(domain.sld == "example")
2218
}
2319

2420
@Test("Successfully creates domain from labels")
2521
func testCreateFromLabels() throws {
2622
let domain = try Domain(labels: ["mail", "example", "com"])
2723
#expect(domain.name == "mail.example.com")
28-
#expect(domain.isStandardDomain)
29-
#expect(domain.tld == "com")
30-
#expect(domain.sld == "example")
31-
}
32-
33-
@Test("Successfully creates domain from RFC1035")
34-
func testCreateFromRFC1035() throws {
35-
let rfc1035 = try Domain.RFC1035("example.com")
36-
let domain = try Domain(rfc1035: rfc1035)
37-
#expect(domain.name == "example.com")
38-
#expect(domain.rfc1035?.name == "example.com")
39-
#expect(domain.rfc1123?.name == "example.com")
40-
#expect(domain.rfc5321.name == "example.com")
41-
}
42-
43-
@Test("Successfully creates domain from RFC1123")
44-
func testCreateFromRFC1123() throws {
45-
let rfc1123 = try Domain.RFC1123("example.com")
46-
let domain = try Domain(rfc1123: rfc1123)
47-
#expect(domain.rfc1035 == nil)
48-
#expect(domain.rfc1123?.name == "example.com")
49-
#expect(domain.rfc5321.name == "example.com")
50-
}
51-
52-
@Test("Successfully creates domain from RFC5321")
53-
func testCreateFromRFC5321() throws {
54-
let rfc5321 = try Domain.RFC5321("[192.168.1.1]")
55-
let domain = Domain(rfc5321: rfc5321)
56-
#expect(domain.rfc1035 == nil)
57-
#expect(domain.rfc1123 == nil)
58-
#expect(domain.rfc5321.name == "[192.168.1.1]")
59-
#expect(domain.isAddressLiteral)
6024
}
6125

6226
@Test("Successfully handles subdomain relationship")
@@ -78,51 +42,13 @@ struct DomainTests {
7842
#expect(subdomain.isSubdomain(of: domain))
7943
}
8044

81-
@Test("Fails to add subdomain to IP address literal")
82-
func testAddSubdomainToIPLiteral() throws {
83-
let domain = try Domain("[192.168.1.1]")
84-
#expect(throws: Domain.DomainError.cannotCreateSubdomain) {
85-
_ = try domain.addingSubdomain("mail")
86-
}
87-
}
88-
8945
@Test("Successfully gets parent domain")
9046
func testParentDomain() throws {
9147
let domain = try Domain("mail.example.com")
9248
let parent = try domain.parent()
9349
#expect(parent?.name == "example.com")
9450
}
9551

96-
@Test("Returns nil parent for top-level domain")
97-
func testNilParentForTopLevel() throws {
98-
let domain = try Domain("example.com")
99-
let parent = try domain.parent()
100-
#expect(parent?.name == "com")
101-
let topLevel = try parent?.parent()
102-
#expect(topLevel == nil)
103-
}
104-
105-
@Test("Successfully handles different RFC format capabilities")
106-
func testRFCFormatCapabilities() throws {
107-
// RFC1035-compliant domain should work with all formats
108-
let rfc1035Domain = try Domain("example.com")
109-
#expect(rfc1035Domain.rfc1035 != nil)
110-
#expect(rfc1035Domain.rfc1123 != nil)
111-
#expect(rfc1035Domain.rfc5321.isStandardDomain)
112-
113-
// Numeric label should work with RFC1123 and RFC5321 only
114-
let numericLabel = try Domain("123.example.com")
115-
#expect(numericLabel.rfc1035 == nil)
116-
#expect(numericLabel.rfc1123 != nil)
117-
#expect(numericLabel.rfc5321.isStandardDomain)
118-
119-
// IP address should work with RFC5321 only
120-
let ipAddress = try Domain("[192.168.1.1]")
121-
#expect(ipAddress.rfc1035 == nil)
122-
#expect(ipAddress.rfc1123 == nil)
123-
#expect(ipAddress.rfc5321.isAddressLiteral)
124-
}
125-
12652
@Test("Successfully encodes and decodes domain")
12753
func testCodable() throws {
12854
let original = try Domain("mail.example.com")
@@ -140,4 +66,11 @@ struct DomainTests {
14066
#expect(fromRaw != nil)
14167
#expect(fromRaw?.name == "example.com")
14268
}
143-
}
69+
70+
@Test("Successfully uses CustomStringConvertible")
71+
func testDescription() throws {
72+
let domain = try Domain("example.com")
73+
#expect(domain.description == "example.com")
74+
#expect("\(domain)" == "example.com")
75+
}
76+
}

Tests/Domain Tests/RFC 1035 Tests.swift

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,116 +8,117 @@
88
@testable import Domain
99
import Foundation
1010
import Testing
11+
import RFC_1035
1112

1213
@Suite("RFC 1035 Domain Tests")
1314
struct RFC1035Tests {
1415
@Test("Successfully creates valid domain")
1516
func testValidDomain() throws {
16-
let domain = try RFC1035.Domain("example.com")
17+
let domain = try RFC_1035.Domain("example.com")
1718
#expect(domain.name == "example.com")
1819
}
1920

2021
@Test("Successfully creates subdomain")
2122
func testValidSubdomain() throws {
22-
let domain = try RFC1035.Domain("sub.example.com")
23+
let domain = try RFC_1035.Domain("sub.example.com")
2324
#expect(domain.name == "sub.example.com")
2425
}
2526

2627
@Test("Successfully gets TLD")
2728
func testTLD() throws {
28-
let domain = try RFC1035.Domain("example.com")
29+
let domain = try RFC_1035.Domain("example.com")
2930
#expect(domain.tld?.stringValue == "com")
3031
}
3132

3233
@Test("Successfully gets SLD")
3334
func testSLD() throws {
34-
let domain = try RFC1035.Domain("example.com")
35+
let domain = try RFC_1035.Domain("example.com")
3536
#expect(domain.sld?.stringValue == "example")
3637
}
3738

3839
@Test("Fails with empty domain")
3940
func testEmptyDomain() throws {
40-
#expect(throws: RFC1035.Domain.ValidationError.empty) {
41-
_ = try RFC1035.Domain("")
41+
#expect(throws: RFC_1035.Domain.ValidationError.empty) {
42+
_ = try RFC_1035.Domain("")
4243
}
4344
}
4445

4546
@Test("Fails with too many labels")
4647
func testTooManyLabels() throws {
4748
let longDomain = Array(repeating: "a", count: 128).joined(separator: ".")
48-
#expect(throws: RFC1035.Domain.ValidationError.tooManyLabels) {
49-
_ = try RFC1035.Domain(longDomain)
49+
#expect(throws: RFC_1035.Domain.ValidationError.tooManyLabels) {
50+
_ = try RFC_1035.Domain(longDomain)
5051
}
5152
}
5253

5354
@Test("Fails with too long domain")
5455
func testTooLongDomain() throws {
5556
let longLabel = String(repeating: "a", count: 63)
5657
let longDomain = Array(repeating: longLabel, count: 5).joined(separator: ".")
57-
#expect(throws: RFC1035.Domain.ValidationError.tooLong(319)) {
58-
_ = try RFC1035.Domain(longDomain)
58+
#expect(throws: RFC_1035.Domain.ValidationError.tooLong(319)) {
59+
_ = try RFC_1035.Domain(longDomain)
5960
}
6061
}
6162

6263
@Test("Fails with invalid label starting with hyphen")
6364
func testInvalidLabelStartingWithHyphen() throws {
64-
#expect(throws: RFC1035.Domain.ValidationError.invalidLabel("-example")) {
65-
_ = try RFC1035.Domain("-example.com")
65+
#expect(throws: RFC_1035.Domain.ValidationError.invalidLabel("-example")) {
66+
_ = try RFC_1035.Domain("-example.com")
6667
}
6768
}
6869

6970
@Test("Fails with invalid label ending with hyphen")
7071
func testInvalidLabelEndingWithHyphen() throws {
71-
#expect(throws: RFC1035.Domain.ValidationError.invalidLabel("example-")) {
72-
_ = try RFC1035.Domain("example-.com")
72+
#expect(throws: RFC_1035.Domain.ValidationError.invalidLabel("example-")) {
73+
_ = try RFC_1035.Domain("example-.com")
7374
}
7475
}
7576

7677
@Test("Successfully detects subdomain relationship")
7778
func testIsSubdomain() throws {
78-
let parent = try RFC1035.Domain("example.com")
79-
let child = try RFC1035.Domain("sub.example.com")
79+
let parent = try RFC_1035.Domain("example.com")
80+
let child = try RFC_1035.Domain("sub.example.com")
8081
#expect(child.isSubdomain(of: parent))
8182
}
8283

8384
@Test("Successfully adds subdomain")
8485
func testAddSubdomain() throws {
85-
let domain = try RFC1035.Domain("example.com")
86+
let domain = try RFC_1035.Domain("example.com")
8687
let subdomain = try domain.addingSubdomain("sub")
8788
#expect(subdomain.name == "sub.example.com")
8889
}
8990

9091
@Test("Successfully gets parent domain")
9192
func testParentDomain() throws {
92-
let domain = try RFC1035.Domain("sub.example.com")
93+
let domain = try RFC_1035.Domain("sub.example.com")
9394
let parent = try domain.parent()
9495
#expect(parent?.name == "example.com")
9596
}
9697

9798
@Test("Successfully gets root domain")
9899
func testRootDomain() throws {
99-
let domain = try RFC1035.Domain("sub.example.com")
100+
let domain = try RFC_1035.Domain("sub.example.com")
100101
let root = try domain.root()
101102
#expect(root?.name == "example.com")
102103
}
103104

104105
@Test("Successfully creates domain from root components")
105106
func testRootInitializer() throws {
106-
let domain = try RFC1035.Domain.root("example", "com")
107+
let domain = try RFC_1035.Domain.root("example", "com")
107108
#expect(domain.name == "example.com")
108109
}
109110

110111
@Test("Successfully creates domain from subdomain components")
111112
func testSubdomainInitializer() throws {
112-
let domain = try RFC1035.Domain.subdomain("com", "example", "sub")
113+
let domain = try RFC_1035.Domain.subdomain("com", "example", "sub")
113114
#expect(domain.name == "sub.example.com")
114115
}
115116

116117
@Test("Successfully encodes and decodes")
117118
func testCodable() throws {
118-
let original = try RFC1035.Domain("example.com")
119+
let original = try RFC_1035.Domain("example.com")
119120
let encoded = try JSONEncoder().encode(original)
120-
let decoded = try JSONDecoder().decode(RFC1035.Domain.self, from: encoded)
121+
let decoded = try JSONDecoder().decode(RFC_1035.Domain.self, from: encoded)
121122
#expect(original == decoded)
122123
}
123124
}

0 commit comments

Comments
 (0)