Swiftpack.co -  Sunlace/swift-syntax-simplified as Swift Package
Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
Sunlace/swift-syntax-simplified
SwiftSyntax without the boilerplate
.package(url: "https://github.com/Sunlace/swift-syntax-simplified.git", from: "2.1.0-0.50400")

SwiftSyntaxSimplified

SwiftSyntax without the boilerplate.

Setup

Choose a version

This library uses a compound version number, with two parts separated by a dash -.

  • The first part is a standard three-part semantic version number X.Y.Z.
  • The second part is the version of SwiftSyntax that it is compatible with.

For example: 1.0.1-0.50300.0 is the 1.0.1 version compatible with the 0.503000.0 version of SwiftSyntax.

Add as a Swift Package Manager dependency

Update your Package.swift, replacing <version number> with the version you chose above.

Package(
    ...,
    dependencies: [
        ...,
        .package(
            name: "SwiftSyntaxSimplified",
            url: "https://github.com/Sunlace/swift-syntax-simplified.git",
            .exact("<version number>")
        ),
    ],
    targets: [
        ...,
        .target(
            ...,
            dependencies: [
                ...,
                .product(name: "SwiftSyntaxSimplified", package: "SwiftSyntaxSimplified"),
            ]
        ),
    ]
)

Import in your code

This library does not replace all the functionality of SwiftSyntax, so do not remove your existing imports of SwiftSyntax.

import SwiftSyntax
import SwiftSyntaxSimplified

Usage

Convert easily between typed and type-erased objects

SwiftSyntax has both typed and type-erased views of all Syntax objects, used throughout its API. With SwiftSyntaxSimplified, you can convert between them on demand.

For example, many of the SyntaxVisitor APIs pass typed arguments but expect type-erased return values:

override func visit(_ node: IfStmtSyntax) -> StmtSyntax {
    return node.withConditions(<conditions>).typeErased
}

Other APIs return type-erased values that must be converted to typed before anything useful can be done:

override func visit(_ node: OptionalChainingExprSyntax) -> ExprSyntax {
    switch node.expression.typed {
    case let stringLiteral as StringLiteralExprSyntax: <action>
    case let functionCall as FunctionCallExprSyntax: <action>
    ...
    }
}

Use the simplified factory methods

SwiftSyntax defines extremely verbose factory methods for creating syntax objects. With SwiftSyntaxSimplified, you can call the same methods that you would normally call, but with less boilerplate.

This:

SyntaxFactory.Simplified.makeFunctionCallExpr(
    calledExpression: <expression>,
    arguments: [
        SyntaxFactory.Simplified.makeTupleExprElement(
            expression:<expression>
        ),
        SyntaxFactory.Simplified.makeTupleExprElement(
            label: <token>,
            expression: <expression>
        ),
    ]
)

Instead of this:

SyntaxFactory.makeFunctionCallExpr(
    calledExpression: <expression>,
    leftParen: SyntaxFactory.makeLeftParenToken(),
    argumentList: SyntaxFactory.makeTupleExprElementList([
        SyntaxFactory.makeTupleExprElement(
            label: nil,
            colon: nil,
            expression: <expression>,
            trailingComma: SyntaxFactory.makeCommaToken()
        ),
        SyntaxFactory.makeTupleExprElement(
            label: <token>,
            colon: SyntaxFactory.makeColonToken(),
            expression: <expression>,
            trailingComma: nil
        )
    ]),
    rightParen: SyntaxFactory.makeRightParenToken(),
    trailingClosure: nil,
    additionalTrailingClosures: nil
)

Factory Method Simplifications

This library duplicates SyntaxFactory.make<X>(...) methods as SyntaxFactory.Simplified.make<X>(...)

For each duplicated method, it applies the following interface simplifications, in order. If no simplifications can be made, the method is not duplicated.

Steps

  1. If a method contains an Optional<TokenSyntax> parameter named trailing<X> that must always be a specific token or nil, depending on the position of the returned object in a list object (i.e. whether it is the last item in that list)
    • remove the parameter
    • duplicate the object definition <X>Syntax as SyntaxFactory.Simplified.<X>Syntax, with fields matching the SyntaxFactory.Simplified.make<X>(...) parameters (including all modifications)
    • return an instance of SyntaxFactory.Simplified.<X>Syntax instead of <X>Syntax.
  2. If a parameter is an Array<X> where X is a type that was duplicated in an above step
    • replace the parameter type Array<X> with Array<SyntaxFactory.Simplified.X>
  3. If a parameter is a TokenSyntax and must always be a specific token
    • remove the parameter
  4. If a parameter is an Optional<TokenSyntax> and must always be a specific token or nil:
    • replace the Optional<TokenSyntax> parameter type with Bool
    • prepend include to the parameter name
    • specify a default value of false
  5. If a parameter is a TokenSyntax and must always be one of a specific set of tokens
    • create a <X>Token enum to represent the options
    • replace the TokenSyntax parameter type with <X>Token>
  6. If a parameter is a Optional<TokenSyntax> and must always be one of a specific set of tokens or nil
    • create a <X>Token enum to represent the non-nil options
    • replace the Optional<TokenSyntax> parameter type with Optional<<X>Token>
  7. If a parameter is an Optional
    • specify a default value of nil
  8. If a parameter is an Array
    • specify a default value of []
  9. If a parameter is of a type that has a SyntaxFactory.Simplified.make<X>(...) method which, after modifications, has zero parameters:
    • remove the parameter
  10. If a parameter is of a type that has a SyntaxFactory.Simplified.make<X>(...) method which, after modifications, has one parameter:
    • replace the parameter type with the parameter type of the SyntaxFactory.Simplified.make<X>(...) method
    • append the parameter name of the SyntaxFactory.Simplified.make<X>(...) method to the parameter name
  11. If an object may be constructed in two different ways that both result in valid Swift
    • add a new parameter <Z> of type Bool where true corresponds to the more verbose option
    • specify a default value of false
  12. If a parameter must be a specific value if another parameter of type Optional<Y> is nil:
    • remove the parameter
    • create a new model object SyntaxFactory.Simplified.<Z>GroupSyntax
    • create a new SyntaxFactory.Simplified.make<Z>Group(...) method with:
      • a copy of the parameter
      • a copy of the other parameter, but with the non-Optional type <Y>
    • replace the other parameter's parameter type Optional<Y> with Optional<SyntaxFactory.Simplified.<Z>GroupSyntax>

Contributing

This library is incomplete, and contributions are welcome! We are actively reviewing PRs, and will merge any that:

  • adds new methods making the improvements described in the Philosphy section
  • fixes issues in the existing code

If you have ideas for other improvements, please open an issue or a PR. However, consistency across the API is our top concern, so any architectural changes should include equivalent changes to all existing code and, if appropriate, a new major version number.

GitHub

link
Stars: 5
Last commit: 6 days ago

Ad: Job Offers

iOS Software Engineer @ Perry Street Software
Perry Street Software is Jack’d and SCRUFF. We are two of the world’s largest gay, bi, trans and queer social dating apps on iOS and Android. Our brands reach more than 20 million members worldwide so members can connect, meet and express themselves on a platform that prioritizes privacy and security. We invest heavily into SwiftUI and using Swift Packages to modularize the codebase.

Dependencies

Release Notes

2.0.0-0.50300
6 weeks ago

Add type erasure (see README.md)

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API