Sourcery Documentation

repository·master·Indexed 27 days ago

https://github.com/krzysztofzablocki/sourcery

A code generator for the Swift language built on Apple's SwiftSyntax. Sourcery allows developers to automate the generation of boilerplate code, such as Mocks, Equality, and Codable conformance, using Stencil templates. It can be installed via Homebrew, CocoaPods, Mint, pre-commit, Swift Package Manager, or as a binary.

Tokens
9.4K
Snippets
27
Records
49
Agent score
92%

What's inside Sourcery

  1. Understand known vs unknown types

    master

    Sourcery distinguishes between types based on whether they were included in the scan targets:

    • Known Types: Types defined within the scanned paths or targets. Sourcery provides a full Type object for these, containing details about protocols, properties, methods, inheritance, etc.
    • Unknown Types: Types defined outside of scanned sources. For these, Sourcery only provides a typeName property; the type property will be nil.

    Note on Extensions: If you define an extension for an unknown type within a scanned source, Sourcery creates a Type object with kind set to extension. This object only contains the declarations defined within that specific extension.

  2. Customize encoding with encode(to:)

    master

    The template generates encode(to:) automatically. You can customize the encoding process using these methods:

    • Nested Containers: Define func encodingContainer(_ encoder: Encoder) -> KeyedEncodingContainer<CodingKeys> to encode into a nested key path.
    • Manual Property Encoding: Define func encodePropertyName(to container: inout KeyedEncodingContainer<CodingKeys>) or func encodePropertyName(to encoder: Encoder) throws to handle custom encoding logic for a specific property.
    • Additional Values: Define func encodeAdditionalValues(to container: inout KeyedEncodingContainer<CodingKeys>) throws or func encodeAdditionalValues(to encoder: Encoder) throws to encode computed properties or constants. This method is called at the end of the generated encoding method.
    • Skip Keys: To prevent certain stored properties (like constants) from being encoded, define an enum SkipEncodingKeys containing the cases to be ignored.
    struct MyStruct: AutoCodable {
        let value: Int
        let skipValue: Int
    
        enum SkipEncodingKeys {
            case skipValue
        }
    }
  3. Generate precise property-level diffs in tests using the Diffable template

    master

    Use the Diffable.stencil template to generate code that provides precise, property-level differences during test failures. Instead of receiving a large block of text when an equality check fails, this template uses the Sourcery Diffable implementation to highlight exactly which properties differ between two objects.

    To implement this, you must use the provided Diffable.stencil template in your Sourcery configuration.

  4. Annotate code with Source Annotations

    master

    You can use // sourcery: comments to provide metadata to your templates.

    Annotation Formats

    • Simple: // sourcery: skipPersistence
    • Key-Value: // sourcery: key = value (e.g., // sourcery: jsonKey = "id")
    • Namespaced: // sourcery: decoding: key = "id" (access as annotations.decoding.key)
    • Inline (End of line): var name: String // sourcery: skip
    • Sectioned:
      // sourcery:begin: skipEquality
      var field1: Int
      var field2: String
      // sourcery:end
    • File-wide: // sourcery:file: skipAll at the top of the file.

    Accessing Annotations in Templates

    In Stencil, access them via the annotations dictionary:

    {% if variable|annotated:"jsonKey" %}
      var local{{ variable.name|capitalize }} = json["{{ variable.annotations.jsonKey }}"]
    {% endif %}
    {% if variable|annotated:"jsonKey" %}
      var local{{ variable.name|capitalize }} = json["{{ variable.annotations.jsonKey }}"] as? {{ variable.typeName }}
    {% endif %}
  5. Generate `Hashable` implementations using AutoHashable

    master

    Use the AutoHashable template to automatically generate :Hashable conformance for your types, eliminating boilerplate code.

    • For Types: It adds the :Hashable conformance to all types that conform to the :AutoHashable protocol.
    • For Protocols: It generates a var hashValue comparator (it does not turn protocols into PATs).

    Variable Annotations

    You can control which properties are included in the hash calculation using the following annotations in your source code:

    • skipHashing: Prevents a specific variable from being included in the hash comparison.
    • includeInHashing: (Enums only) Allows you to include a computed variable in the hashing logic.
    // Example of what the generated output looks like:
    // MARK: - AdNodeViewModel AutoHashable
    extension AdNodeViewModel: Hashable {
    
        internal var hashValue: Int {
            return combineHashes(remoteAdView.hashValue, hidesDisclaimer.hashValue, type.hashValue, height.hashValue, attributedDisclaimer.hashValue, 0)
        }
    }
  6. Generate custom CodingKeys for structs

    master

    If you need to map specific properties to different JSON keys, define a CodingKeys enum. You can use Sourcery inline annotations to let the template generate the remaining keys automatically.

    Use // sourcery:inline:auto:TypeName.CodingKeys.AutoCodable to mark the start of the generated keys and // sourcery:end to mark the end.

    struct Person: AutoDecodable {
        let id: String
        let firstName: Bool
        let surname: String
    
        enum CodingKeys: String, CodingKey {
            // this is the custom key that you define manually
            case firstName = "first_name"
    
    // sourcery:inline:auto:Person.CodingKeys.AutoCodable
            // the rest is generated by the template
            case id
            case surname
    // sourcery:end
        }
    }
  7. Generate `LinuxMain.swift` for Swift tests on Linux

    master

    To support test execution on Linux, you can use Sourcery to generate a LinuxMain.swift file. This process generates an allTests static variable for every test case and passes them as XCTestCaseEntry to XCTMain.

    To ensure your test modules are correctly imported in the generated file, run Sourcery with the --args testimports='import YourModuleName' parameter.

  8. Generate Equatable implementation using AutoEquatable

    master

    You can automatically generate Equatable conformance for your types using the AutoEquatable template. This template applies to any type that either conforms to the AutoEquatable protocol or is marked with the AutoEquatable source annotation.

    Behavior:

    • For classes and structs, it adds : Equatable conformance and implements the == operator.
    • For protocols, it only generates the func == implementation (to avoid converting them into Protocol-Oriented Programming/PATs).

    Variable Annotations: When writing your templates or using annotations, you can control how specific properties are handled:

    • skipEquality: Skips a specific variable from being included in the equality comparison.
    • arrayEquality: Used for arrays of items that do not implement Equatable themselves but do have a == operator available (e.g., arrays of protocols).
    // Example of generated output for a type conforming to AutoEquatable
    // MARK: - AdNodeViewModel AutoEquatable
    extension AdNodeViewModel: Equatable {}
    
    internal func == (lhs: AdNodeViewModel, rhs: AdNodeViewModel) -> Bool {
        guard lhs.remoteAdView == rhs.remoteAdView else { return false }
        guard lhs.hidesDisclaimer == rhs.hidesDisclaimer else { return false }
        guard lhs.type == rhs.type else { return false }
        guard lhs.height == rhs.height else { return false }
    
        guard lhs.attributedDisclaimer == rhs.attributedDisclaimer else { return false }
    
        return true
    }