👍 Thanks for taking the time to contribute to Swift Inspector! 👍
This document explains some of the guidelines around contributing to this project as well as how this project is structured, so you can jump in!
We ask you that if you have an idea for a new feature you open an issue.
Whenever your feature is ready for review, please open a PR with a clear list of what you've done.
For any change you make, we ask you to also add corresponding unit tests.
SwiftInspector is divided into four main parts:
Contains the main executable for this command line tool. It only contains the entry point main.swift
file.
Contains all the files for managing commands and options for these commands. We can think of this as the frontend of this project.
Comprises this project's analyzers. Any file related to analyzing Swift code should be put here. This is the layer that the Command interacts with directly.
Comprises this project's syntax visitors. Any file that visits Swift syntax nodes should be put here. Analyzers should use the visitors in this module.
To add a new command create a YourCommand.swift
file inside SwiftInspectorCommand
and add it to the InspectorCommand
subcommands. Your command should delegate to SwiftInspectorAnalyzer
for all the logic related to analyzing Swift code.
When you're ready to write a new command, I suggest you start by writing unit tests by relying on the TestTask.swift file to create fake commands with arguments:
private struct YourNewCommand {
fileprivate static func run(path: String, arguments: [String] = []) throws -> TaskStatus {
let arguments = ["newcommand", "--path", path] + arguments
return try TestTask.run(withArguments: arguments)
}
}
Refer to the tests in the Commands target for examples.
Since we want to separate the commands from the analyzer functionality, you should abstract your analyzer functionality in a class that lives in SwiftInspectorAnalyzer
. Analyzers are a thin bridge between commands and syntax visitors – they are responsible for kicking off syntax visitation and then packaging up and returning the information gathered from syntax visitors.
Code that visits Swift syntax nodes should be live in the SwiftInspectorVisitors
module.
I suggest relying on the Swift AST Explorer to understand the AST better and play around with different use cases.
When you're ready to write some code, I suggest you to start by writing unit tests by relying on the Temporary.swift file to create fake files for testing.
context("when something happens") {
beforeEach {
fileURL = try! Temporary.makeFile(
content: """
typealias SomeTypealias = TypeA & TypeB
"""
)
}
it("something happens") {
let result = try? sut.analyze(fileURL: fileURL)
expect(result) == Something
}
}
Refer to the tests in the Analyzer target for examples.
- We use Quick and Nimble in this repo, we rely on the following convention:
- Use
describe
blocks for each internal and public method - Use
context
to setup different scenarios (e.g. "when A happens") - Only use one assert per test whenever possible
- Use