diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a0254786..998a0ebe 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,14 +1,5 @@ version: 2 -enable-beta-ecosystems: true updates: - - package-ecosystem: "swift" - directory: "/" - schedule: - interval: "daily" - groups: - dependencies: - patterns: - - "*" - package-ecosystem: "github-actions" directory: "/" schedule: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 02c52fc2..aa48ea6c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,13 +10,13 @@ env: SWIFT_DETERMINISTIC_HASHING: 1 jobs: - unit-tests: uses: vapor/ci/.github/workflows/run-unit-tests.yml@main + secrets: inherit upstream-check: runs-on: ubuntu-latest - container: swift:5.9-jammy + container: swift:5.10-jammy steps: - name: Check out self uses: actions/checkout@v4 diff --git a/Package.swift b/Package.swift index 4653f721..cf1a2dc6 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.7 +// swift-tools-version:5.8 import PackageDescription let package = Package( @@ -16,9 +16,15 @@ let package = Package( .package(url: "https://github.com/apple/swift-log.git", from: "1.5.3") ], targets: [ - .target(name: "RoutingKit", dependencies: [ - .product(name: "Logging", package: "swift-log"), - ]), - .testTarget(name: "RoutingKitTests", dependencies: ["RoutingKit"]), + .target( + name: "RoutingKit", + dependencies: [ + .product(name: "Logging", package: "swift-log"), + ] + ), + .testTarget( + name: "RoutingKitTests", + dependencies: ["RoutingKit"] + ), ] ) diff --git a/Package@swift-5.9.swift b/Package@swift-5.9.swift index 2bfc3228..2eac190e 100644 --- a/Package@swift-5.9.swift +++ b/Package@swift-5.9.swift @@ -22,12 +22,14 @@ let package = Package( .product(name: "Logging", package: "swift-log"), ], swiftSettings: [ + .enableUpcomingFeature("ExistentialAny"), .enableExperimentalFeature("StrictConcurrency=complete"), ]), .testTarget( name: "RoutingKitTests", dependencies: ["RoutingKit"], swiftSettings: [ + .enableUpcomingFeature("ExistentialAny"), .enableExperimentalFeature("StrictConcurrency=complete"), ] ), diff --git a/README.md b/README.md index dc6463f6..85a703fe 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,17 @@

- - - - RoutingKit - -
-
-Documentation -Team Chat -MIT License -Continuous Integration - -Swift 5.7 - 5.9 + + + + RoutingKit + +
+
+Documentation +Team Chat +MIT License +Continuous Integration + +Swift 5.8+

+
diff --git a/Sources/RoutingKit/Docs.docc/Resources/vapor-routingkit-logo.svg b/Sources/RoutingKit/Docs.docc/Resources/vapor-routingkit-logo.svg new file mode 100644 index 00000000..56d2e87c --- /dev/null +++ b/Sources/RoutingKit/Docs.docc/Resources/vapor-routingkit-logo.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/Sources/RoutingKit/Docs.docc/theme-settings.json b/Sources/RoutingKit/Docs.docc/theme-settings.json new file mode 100644 index 00000000..79054c92 --- /dev/null +++ b/Sources/RoutingKit/Docs.docc/theme-settings.json @@ -0,0 +1,21 @@ +{ + "theme": { + "aside": { "border-radius": "16px", "border-style": "double", "border-width": "3px" }, + "border-radius": "0", + "button": { "border-radius": "16px", "border-width": "1px", "border-style": "solid" }, + "code": { "border-radius": "16px", "border-width": "1px", "border-style": "solid" }, + "color": { + "routingkit": "#f00", + "documentation-intro-fill": "radial-gradient(circle at top, var(--color-routingkit) 30%, #000 100%)", + "documentation-intro-accent": "var(--color-routingkit)", + "logo-base": { "dark": "#fff", "light": "#000" }, + "logo-shape": { "dark": "#000", "light": "#fff" }, + "fill": { "dark": "#000", "light": "#fff" } + }, + "icons": { "technology": "/routingkit/images/vapor-routingkit-logo.svg" } + }, + "features": { + "quickNavigation": { "enable": true }, + "i18n": { "enable": true } + } +} diff --git a/Sources/RoutingKit/Parameters.swift b/Sources/RoutingKit/Parameters.swift index 200aa1ec..bc51fbb4 100644 --- a/Sources/RoutingKit/Parameters.swift +++ b/Sources/RoutingKit/Parameters.swift @@ -4,41 +4,42 @@ import Logging /// Holds dynamic path components that were discovered while routing. /// /// After this struct has been filled with parameter values, you can fetch -/// them out by name using `get(_:)`. +/// them out by name using ``get(_:)`` or ``get(_:as:)``. /// /// let postID = parameters.get("post_id") /// public struct Parameters: Sendable { /// Internal storage. private var values: [String: String] - private var catchall: Catchall + private var catchall: [String] + + /// The configured logger. public let logger: Logger /// Return a list of all parameter names which were captured. Does not include values listed in the catchall. public var allNames: Set { .init(self.values.keys) } - /// Creates a new `Parameters`. + /// Create a new `Parameters`. /// - /// Pass this into the `Router.route(path:parameters:)` method to fill with values. + /// Pass this to ``Router/route(path:parameters:)`` to fill with values. public init() { - self.values = [:] - self.catchall = Catchall() - self.logger = Logger(label: "codes.vapor.routingkit") + self.init(nil) } - /// Creates a new `Parameters`. - /// Pass this into the `Router.route(path:parameters:)` method to fill with values. - /// - Parameters: - /// - logger: The logger to be used. If none is provided, a default one will be created. + /// Create a new `Parameters`. + /// + /// Pass this to ``Router/route(path:parameters:)`` to fill with values. + /// + /// - Parameter logger: The logger to be used. If none is provided, a default one will be created. public init(_ logger: Logger?) { self.values = [:] - self.catchall = Catchall() - self.logger = logger ?? Logger(label: "codes.vapor.routingkit") + self.catchall = [] + self.logger = logger ?? .init(label: "codes.vapor.routingkit") } /// Grabs the named parameter from the parameter bag. /// - /// For example GET /posts/:post_id/comments/:comment_id + /// For example `GET /posts/:post_id/comments/:comment_id` /// would be fetched using: /// /// let postID = parameters.get("post_id") @@ -51,27 +52,25 @@ public struct Parameters: Sendable { /// Grabs the named parameter from the parameter bag, casting it to /// a `LosslessStringConvertible` type. /// - /// For example GET /posts/:post_id/comments/:comment_id + /// For example `GET /posts/:post_id/comments/:comment_id` /// would be fetched using: /// /// let postID = parameters.get("post_id", as: Int.self) /// let commentID = parameters.get("comment_id", as: Int.self) /// - public func get(_ name: String, as type: T.Type = T.self) -> T? - where T: LosslessStringConvertible - { + public func get(_ name: String, as type: T.Type = T.self) -> T? { self.get(name).flatMap(T.init) } /// Adds a new parameter value to the bag. /// - /// - note: The value will be percent-decoded. + /// > Note: The value will be percent-decoded. /// - /// - parameters: + /// - Parameters: /// - name: Unique parameter name /// - value: Value (percent-encoded if necessary) public mutating func set(_ name: String, to value: String?) { - self.values[name] = value?.removingPercentEncoding + self.values[name] = value.map { $0.removingPercentEncoding ?? $0 } } /// Fetches the components matched by `catchall` (`**`). @@ -85,30 +84,17 @@ public struct Parameters: Sendable { /// // not hit /// } /// - /// - note: The value will be percent-decoded. + /// > Note: The value will be percent-decoded. /// - /// - returns: The path components matched - public mutating func getCatchall() -> [String] { - if self.catchall.isPercentEncoded { - self.catchall.values = self.catchall.values.map { $0.removingPercentEncoding ?? $0 } - self.catchall.isPercentEncoded = false - } - return self.catchall.values + /// - Returns: The path components matched. + public func getCatchall() -> [String] { + self.catchall } /// Stores the components matched by `catchall` (`**`). /// - /// - parameters: - /// - matched: The subpaths matched (percent-encoded if necessary) + /// - Parameter matched: The subpaths matched (percent-encoded if necessary) public mutating func setCatchall(matched: [String]) { - self.catchall = Catchall(values: matched) - } - - /// Holds path components that were matched by `catchall` (`**`). - /// - /// Used internally. - private struct Catchall { - var values: [String] = [] - var isPercentEncoded: Bool = true + self.catchall = matched.map { $0.removingPercentEncoding ?? $0 } } }