Skip to content

Commit 5aed5a1

Browse files
committed
Doc updates
1 parent 689e6f7 commit 5aed5a1

9 files changed

Lines changed: 164 additions & 23 deletions

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
/.build
33
/Packages
44
/*.xcodeproj
5-
.swiftpm
5+
.swiftpm
6+
build/
7+
docs/

Sources/SwiftHooks/Commands/Command+Permissions.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/// Check if the given user has the permission to execute the command.
2+
///
3+
/// let checker = MyChecker()
4+
/// guard checker.check(user, canUse: command, on: event) else { throw CommandError.InvalidPermissions }
5+
///
16
public protocol CommandPermissionChecker {
27

38
/// Check if the given user has the permission to execute the command.
@@ -11,7 +16,7 @@ public protocol CommandPermissionChecker {
1116
/// - event: Event holding the command & related info
1217
///
1318
/// - Returns: Wether or not the user is allowed to execute the command
14-
func check(_ user: Userable, canUse command: Command, on event: CommandEvent) -> Bool
19+
func check(_ user: Userable, canUse command: _ExecutableCommand, on event: CommandEvent) -> Bool
1520
}
1621

1722
/// Checks if a user is allowed to execute based on their ID
@@ -27,7 +32,7 @@ public struct IDChecker: CommandPermissionChecker {
2732
/// List of whitelisted IDs
2833
let ids: [String]
2934

30-
public func check(_ user: Userable, canUse command: Command, on event: CommandEvent) -> Bool {
35+
public func check(_ user: Userable, canUse command: _ExecutableCommand, on event: CommandEvent) -> Bool {
3136
guard let id = user.identifier else { return false }
3237
return ids.contains(id)
3338
}

Sources/SwiftHooks/Commands/Command.swift

Lines changed: 81 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// Base command
12
public struct Command: ExecutableCommand {
23
public let name: String
34
public let group: String?
@@ -23,6 +24,10 @@ public struct Command: ExecutableCommand {
2324
self.closure = closure
2425
}
2526

27+
/// Create a new command.
28+
///
29+
/// - parameters:
30+
/// - name: Name and trigger of the command.
2631
public init(_ name: String) {
2732
self.name = name
2833
self.group = nil
@@ -34,10 +39,18 @@ public struct Command: ExecutableCommand {
3439

3540
public func validate() throws { }
3641

37-
public func arg<A>(_ t: A.Type, named n: String) -> OneArgCommand<A> {
38-
let x = GenericCommandArgument<A>(componentType: A.typedName, componentName: n)
42+
/// Add an argument to this command
43+
///
44+
/// Command("echo")
45+
/// .arg(String.Consuming.self, named: "content")
46+
///
47+
/// - parameters:
48+
/// - t: Type of the argument.
49+
/// - name: Name of the argument.
50+
public func arg<A>(_ t: A.Type, named name: String) -> OneArgCommand<A> {
51+
let x = GenericCommandArgument<A>(componentType: A.typedName, componentName: name)
3952
return OneArgCommand<A>(
40-
name: name,
53+
name: self.name,
4154
group: group,
4255
alias: alias,
4356
hookWhitelist: hookWhitelist,
@@ -72,6 +85,7 @@ fileprivate extension ExecutableCommand {
7285
}
7386
}
7487

88+
/// Base command with one argument
7589
public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConvertible {
7690
public let name: String
7791
public let group: String?
@@ -107,20 +121,29 @@ public struct OneArgCommand<A>: ExecutableCommand where A: CommandArgumentConver
107121
try closure(hooks, event, a)
108122
}
109123

110-
public func arg<B>(_ t: B.Type, named: String) -> TwoArgCommand<A, B> {
124+
/// Add an argument to this command
125+
///
126+
/// Command("echo")
127+
/// .arg(String.Consuming.self, named: "content")
128+
///
129+
/// - parameters:
130+
/// - t: Type of the argument.
131+
/// - name: Name of the argument.
132+
public func arg<B>(_ t: B.Type, named name: String) -> TwoArgCommand<A, B> {
111133
return TwoArgCommand<A, B>(
112-
name: name,
134+
name: self.name,
113135
group: group,
114136
alias: alias,
115137
hookWhitelist: hookWhitelist,
116138
permissionChecks: permissionChecks,
117139
closure: { _, _, _, _ in },
118140
argOne: arg,
119-
argTwo: GenericCommandArgument<B>(componentType: B.typedName, componentName: named)
141+
argTwo: GenericCommandArgument<B>(componentType: B.typedName, componentName: name)
120142
)
121143
}
122144
}
123145

146+
/// Base command with two arguments
124147
public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible {
125148
public let name: String
126149
public let group: String?
@@ -163,21 +186,30 @@ public struct TwoArgCommand<A, B>: ExecutableCommand where A: CommandArgumentCon
163186
try self.closure(hooks, event, a, b)
164187
}
165188

166-
public func arg<C>(_ t: C.Type, named: String) -> ThreeArgCommand<A, B, C> {
189+
/// Add an argument to this command
190+
///
191+
/// Command("echo")
192+
/// .arg(String.Consuming.self, named: "content")
193+
///
194+
/// - parameters:
195+
/// - t: Type of the argument.
196+
/// - name: Name of the argument.
197+
public func arg<C>(_ t: C.Type, named name: String) -> ThreeArgCommand<A, B, C> {
167198
return ThreeArgCommand<A, B, C>(
168-
name: name,
199+
name: self.name,
169200
group: group,
170201
alias: alias,
171202
hookWhitelist: hookWhitelist,
172203
permissionChecks: permissionChecks,
173204
closure: { _, _, _, _, _ in },
174205
argOne: argOne,
175206
argTwo: argTwo,
176-
argThree: GenericCommandArgument<C>(componentType: C.typedName, componentName: named)
207+
argThree: GenericCommandArgument<C>(componentType: C.typedName, componentName: name)
177208
)
178209
}
179210
}
180211

212+
/// Base command with three arguments
181213
public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgumentConvertible, B: CommandArgumentConvertible, C: CommandArgumentConvertible {
182214
public let name: String
183215
public let group: String?
@@ -226,26 +258,36 @@ public struct ThreeArgCommand<A, B, C>: ExecutableCommand where A: CommandArgume
226258
try self.closure(hooks, event, a, b, c)
227259
}
228260

229-
public func arg<T>(_ t: T.Type, named: String) -> ArrayArgCommand where T: CommandArgumentConvertible {
261+
/// Add an argument to this command
262+
///
263+
/// Command("echo")
264+
/// .arg(String.Consuming.self, named: "content")
265+
///
266+
/// - parameters:
267+
/// - t: Type of the argument.
268+
/// - name: Name of the argument.
269+
public func arg<T>(_ t: T.Type, named name: String) -> ArrayArgCommand where T: CommandArgumentConvertible {
230270
return ArrayArgCommand(
231-
name: name,
271+
name: self.name,
232272
group: group,
233273
alias: alias,
234274
hookWhitelist: hookWhitelist,
235275
permissionChecks: permissionChecks,
236276
closure: { _, _, _ in },
237-
arguments: [argOne, argTwo, argThree, GenericCommandArgument<T>(componentType: T.typedName, componentName: named)]
277+
arguments: [argOne, argTwo, argThree, GenericCommandArgument<T>(componentType: T.typedName, componentName: name)]
238278
)
239279
}
240280
}
241281

282+
/// Base command with four or more arguments
242283
public struct ArrayArgCommand: ExecutableCommand {
243284
public let name: String
244285
public let group: String?
245286
public let alias: [String]
246287
public let hookWhitelist: [HookID]
247288
public let permissionChecks: [CommandPermissionChecker]
248289
public let closure: (SwiftHooks, CommandEvent, Arguments) throws -> Void
290+
/// Arguments for this command.
249291
public let arguments: [CommandArgument]
250292

251293
public var readableArguments: String? {
@@ -278,19 +320,29 @@ public struct ArrayArgCommand: ExecutableCommand {
278320
try closure(hooks, event, Arguments(arguments))
279321
}
280322

281-
public func arg<T>(_ t: T.Type, named: String) -> ArrayArgCommand where T: CommandArgumentConvertible {
323+
/// Add an argument to this command
324+
///
325+
/// Command("echo")
326+
/// .arg(String.Consuming.self, named: "content")
327+
///
328+
/// - parameters:
329+
/// - t: Type of the argument.
330+
/// - name: Name of the argument.
331+
public func arg<T>(_ t: T.Type, named name: String) -> ArrayArgCommand where T: CommandArgumentConvertible {
282332
return ArrayArgCommand(
283-
name: name,
333+
name: self.name,
284334
group: group,
285335
alias: alias,
286336
hookWhitelist: hookWhitelist,
287337
permissionChecks: permissionChecks,
288338
closure: { _, _, _ in },
289-
arguments: arguments + GenericCommandArgument<T>(componentType: T.typedName, componentName: named)
339+
arguments: arguments + GenericCommandArgument<T>(componentType: T.typedName, componentName: name)
290340
)
291341
}
292342
}
293343

344+
345+
/// Arguments container used in `ArrayArgCommand`.
294346
public class Arguments {
295347
let arguments: [CommandArgument]
296348
private(set) var nilArgs: [String]
@@ -300,10 +352,20 @@ public class Arguments {
300352
self.nilArgs = []
301353
}
302354

303-
public func getArg<A>(named name: String, on event: CommandEvent) throws -> A where A: CommandArgumentConvertible, A.ResolvedArgument == A {
304-
return try self.get(A.self, named: name, on: event)
305-
}
306-
355+
/// Resolve an argument from the command arguments
356+
///
357+
/// let reason = try args.get(String.self, named: "reason", on: event)
358+
///
359+
/// - parameters:
360+
/// - arg: Type to resolve.
361+
/// - name: Name of the argument to resolve.
362+
/// - event: `CommandEvent` to resolve on.
363+
///
364+
/// - throws:
365+
/// `CommandError.UnableToConvertArgument` when resolving fails.
366+
/// `CommandError.ArgumentNotFound` when no argument is found.
367+
///
368+
/// - returns: The resolved argument.
307369
public func get<A>(_ arg: A.Type, named name: String, on event: CommandEvent) throws -> A.ResolvedArgument where A: CommandArgumentConvertible {
308370
guard let foundArg = self.arguments.first(where: {
309371
$0.componentType == arg.typedName &&

Sources/SwiftHooks/Commands/CommandArgumentConvertible.swift

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ extension CommandArgument {
7878
}
7979
}
8080

81-
81+
/// Any type capable of consuming.
82+
///
83+
/// See also `ConsumingCommandArgumentConvertible`
8284
public protocol AnyConsuming {}
8385
protocol AnyOptionalType {
8486
var isNil: Bool { get }
@@ -122,6 +124,10 @@ extension String: CommandArgumentConvertible {
122124
}
123125

124126
public extension String {
127+
/// Helper to create consuming `String` arguments.
128+
///
129+
/// Command("test")
130+
/// .arg(String.Consuming.self, "consumingString")
125131
struct Consuming: ConsumingCommandArgumentConvertible {
126132
public static var typedName: String {
127133
String.typedName
@@ -134,6 +140,18 @@ public extension String {
134140
}
135141

136142
extension FixedWidthInteger {
143+
144+
/// Attempts to resolve an argument from the provided string.
145+
///
146+
/// - parameters:
147+
/// - argument: String taken from the message body.
148+
/// - event: The `CommandEvent` this argument should be resolved for.
149+
///
150+
/// - throws:
151+
/// `CommandError.UnableToConvertArgument` when `ResolvedArgument` can not be created from `argument`
152+
/// `CommandError.ArgumentNotFound` when no argument is found
153+
///
154+
/// - returns: The resolved argument
137155
public static func resolveArgument(_ argument: String, on event: CommandEvent) throws -> Self {
138156
guard let number = Self(argument) else {
139157
throw CommandError.UnableToConvertArgument(argument, "\(self.self)")
@@ -154,6 +172,18 @@ extension UInt32: CommandArgumentConvertible { }
154172
extension UInt64: CommandArgumentConvertible { }
155173

156174
extension BinaryFloatingPoint {
175+
176+
/// Attempts to resolve an argument from the provided string.
177+
///
178+
/// - parameters:
179+
/// - argument: String taken from the message body.
180+
/// - event: The `CommandEvent` this argument should be resolved for.
181+
///
182+
/// - throws:
183+
/// `CommandError.UnableToConvertArgument` when `ResolvedArgument` can not be created from `argument`
184+
/// `CommandError.ArgumentNotFound` when no argument is found
185+
///
186+
/// - returns: The resolved argument
157187
public static func resolveArgument(_ argument: String, on event: CommandEvent) throws -> Self {
158188
guard let number = Double(argument) else {
159189
throw CommandError.UnableToConvertArgument(argument, "\(self.self)")

Sources/SwiftHooks/Commands/ExecutableCommand.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// Base `ExecutableCommand`
12
public protocol _ExecutableCommand: Commands {
23
/// Help description of the command. Used to explain usage to users.
34
var help: String { get }
@@ -24,7 +25,9 @@ public protocol _ExecutableCommand: Commands {
2425
func invoke(on event: CommandEvent, using hooks: SwiftHooks) throws
2526
}
2627

28+
/// Base `ExecutableCommand`
2729
public protocol ExecutableCommand: _ExecutableCommand {
30+
/// Closure type this command will execute.
2831
associatedtype Execute
2932
/// Closure to execute when command is invoked.
3033
var closure: Execute { get }
@@ -34,9 +37,17 @@ public protocol ExecutableCommand: _ExecutableCommand {
3437
}
3538

3639
public extension ExecutableCommand {
40+
/// Human readable string of arguments required for this command.
41+
///
42+
/// command.readableArguments // "<a:Int> <b:Int> [c:String]"
3743
var readableArguments: String? { return nil }
44+
45+
/// Trigger of the command.
46+
///
47+
/// Synonym for `ExecutableCommand.name`
3848
var trigger: String { name }
3949

50+
/// Human readable help string explaining command usage.
4051
var help: String {
4152
[group, name, readableArguments].compactMap { $0 }.joined(separator: " ").trimmingCharacters(in: .whitespacesAndNewlines)
4253
}

Sources/SwiftHooks/Commands/SwiftHooks+Commands.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public enum CommandError: Error {
5050
/// Thrown from argument decoding
5151
case ArgumentNotFound(String)
5252

53+
/// Retrieve the localized description for this error.
5354
public var localizedDescription: String {
5455
switch self {
5556
case .ArgumentNotFound(let arg):
@@ -64,15 +65,30 @@ public enum CommandError: Error {
6465
}
6566
}
6667

68+
/// Event passed in to a command closure containing required data.
6769
public struct CommandEvent {
70+
/// Refference to `SwiftHooks` instance dispatching this command.
6871
public let hooks: SwiftHooks
72+
/// User that executed the command. Can be downcast to backend specific type.
6973
public let user: Userable
74+
/// String arguments passed in to the command. All space separated strings after the commands trigger.
7075
public let args: [String]
76+
/// Message that executed the command.
7177
public let message: Messageable
78+
/// Full trigger of the command. Either name or name and group.
7279
public let name: String
80+
/// Hook that originally dispatched this command. Can be downcast to backend specific type.
7381
public let hook: _Hook
82+
/// Command specific logger. Has command trigger set as command metadata by default.
7483
public private(set) var logger: Logger
7584

85+
/// Create a new `CommandEvent`
86+
///
87+
/// - parameters:
88+
/// - hooks: `SwiftHooks` instance dispatching this command.
89+
/// - cmd: Command this event is wrapping.
90+
/// - msg: Message that executed the command.
91+
/// - h: `_Hook` that originally dispatched this command.
7692
public init(hooks: SwiftHooks, cmd: _ExecutableCommand, msg: Messageable, for h: _Hook) {
7793
self.logger = Logger(label: "SwiftHooks.Command")
7894
self.hooks = hooks

Sources/SwiftHooks/Listeners/EventListeners.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ public protocol EventListeners {
1010
public struct Listeners: EventListeners {
1111
let listeners: EventListeners
1212

13+
/// Create new `Listeners`
14+
///
15+
/// - parameters:
16+
/// - listeners: `EventListeners` in this group.
1317
public init(@ListenerBuilder listeners: () -> EventListeners) {
1418
self.listeners = listeners()
1519
}

0 commit comments

Comments
 (0)