Kotlin and Java API for generating .swift source files.

Overview

SwiftPoet

GitHub Workflow Status Maven Central Sonatype Nexus (Snapshots) codebeat badge

SwiftPoet is a Kotlin and Java API for generating .swift source files.

Source file generation can be useful when doing things such as annotation processing or interacting with metadata files (e.g., database schemas, protocol formats). By generating code, you eliminate the need to write boilerplate while also keeping a single source of truth for the metadata.

Example

Here's a HelloWorld file:

import RxSwift


class Greeter {

  private let name: String

  init(name: String) {
    self.name = name
  }

  func greet() -> Observable<String> {
    return Observable.from("Hello \(name)")
  }

}

And this is the code to generate it with SwiftPoet:

val observableTypeName = DeclaredTypeName.typeName("RxSwift.Observable")

val testClass = TypeSpec.classBuilder("Greeter")
   .addProperty("name", STRING, Modifier.PRIVATE)
   .addFunction(
      FunctionSpec.constructorBuilder()
         .addParameter("name", STRING)
         .addCode("self.name = name\n")
         .build()
   )
   .addFunction(
      FunctionSpec.builder("greet")
         .returns(observableTypeName.parameterizedBy(STRING))
         .addCode("return %T.from(\"Hello \\(name)\")\n", observableTypeName)
         .build()
   )
   .build()

val file = FileSpec.builder("Greeter")
   .addType(testClass)
   .build()

val out = StringWriter()
file.writeTo(out)

The KDoc catalogs the complete SwiftPoet API, which is inspired by JavaPoet.

Download

Download the latest .jar or depend via Maven:

<dependency>
  <groupId>io.outfoxx</groupId>
  <artifactId>swiftpoet</artifactId>
  <version>1.3.0</version>
</dependency>

or Gradle:

compile 'io.outfoxx:swiftpoet:1.3.0'

Snapshots of the development version are available in Sonatype's snapshots repository.

License

Copyright 2017 Outfox, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • Extensions don't handle imports

    Extensions don't handle imports

    The import for extension types is not added using swiftpoet 1.3.1.

    FileSpec.builder("file")
      .addExtension(
        ExtensionSpec.builder(DeclaredTypeName.typeName("RxSwift.Observable"))
          .build()
      )
      .build()
    

    The generated code is:

    extension RxSwift.Observable {
    }
    

    But it should be:

    import RxSwift
    
    extension RxSwift.Observable {
    }
    
    opened by PaulWoitaschek 10
  • No ways to create @escaping lambda at all

    No ways to create @escaping lambda at all

    To create lambda type i use FunctionTypeName.get but in all variants i can't pass escaping = true and as i see in sources - here no ways to change value after creation and also we can't use constructor from outside. so @escaping lamda can't be created, but logic for write this lambda - already done. need to add some way to change/set escaping flag

    opened by Alex009 5
  • Ignore argumentLabel when equal to parameterName

    Ignore argumentLabel when equal to parameterName

    Declaring a function parameter with the same value for argumentLabel and parameterSpec produces a warning in xcode (often treated as error if the compiler setting is enabled). We should handle this while emitting code and only adding the argumentLabel when its value is different from parameterName

    Screenshot 2022-07-18 at 10 07 02
    opened by francybiga 3
  • Invalid rules for nested types and protocols

    Invalid rules for nested types and protocols

    SwiftPoet implementation checks if the TypeSpec is a protocol when adding a nested type, however that rule is not 100% correct.

    Here is a few scenarios that the current code can't handle correctly:

    Scenario A: The nested type is a typealias

    Protocols are allowed to have type aliases as nested types. Since TypeAliasSpec is a subclass of AnyTypeSpec the current implementation doesn't allow that. The following is a valid construct in Swift that cannot be built with SwiftPoet:

    protocol MyProtocol {
    
      typealias NestedTypeAlias = String
    
    }
    

    Scenario B: Protocol is a nested type of a struct/class/enum

    Protocols can't have nested types (other than type aliases) and cannot in any scenario be a nested type of another construct. The Swift compiler in such scenarios is Protocol 'Nested' cannot be nested inside another declaration. Therefore, the following code is possible to be built using SwiftPoet but it's invalid:

    struct MyStruct {
    
      protocol MyNestedProtocol {
      }
    
    }
    
    opened by drochetti 3
  • class only protocols

    class only protocols

    Hey, just tried to generate a class only protocol:

    protocol Test: class { ... }

    but i think this is not supported (correct me if i'm wrong) since swiftpoet treats the class keyword as a reserved keyword.

    If you wan't i can put a PR together to fix this - Some thoughts: We could just remove class from the reserved keywords and it would be possible but i first wanted to check with you if there would be a more elegant way to do it. Another thought i had was to add a val unsafe: Boolean to the DeclaredTypeName constructor to skip the keyword check.

    What do you think?

    opened by davidkraus 3
  • 1.4.1 crash

    1.4.1 crash

    SwiftPoet 1.4.1 causes this crash. As the code base is very complex and I can't toString the FileSpec I can't easily share a reproducer, but from the stacktrace it's pretty clear what happens. This worked fine in 1.4.0 and is caused by this change: 6da6707818e10677c3738b9dbe8435572eb15e5c

    Caused by: java.lang.IndexOutOfBoundsException: Empty list doesn't contain element at index 0.
    	at kotlin.collections.EmptyList.get(Collections.kt:36)
    	at kotlin.collections.EmptyList.get(Collections.kt:24)
    	at io.outfoxx.swiftpoet.CodeWriter.emitTypeVariables(CodeWriter.kt:159)
    	at io.outfoxx.swiftpoet.FunctionSpec.emitSignature(FunctionSpec.kt:115)
    	at io.outfoxx.swiftpoet.FunctionSpec.emit$swiftpoet(FunctionSpec.kt:62)
    	at io.outfoxx.swiftpoet.FunctionSpec.emit$swiftpoet$default(FunctionSpec.kt:42)
    	at io.outfoxx.swiftpoet.ExtensionSpec.emit$swiftpoet(ExtensionSpec.kt:95)
    	at io.outfoxx.swiftpoet.FileMemberSpec.emit$swiftpoet(FileMemberSpec.kt:41)
    	at io.outfoxx.swiftpoet.FileSpec.emit(FileSpec.kt:96)
    	at io.outfoxx.swiftpoet.FileSpec.writeTo(FileSpec.kt:52)
    	at io.outfoxx.swiftpoet.FileSpec.writeTo(FileSpec.kt:68)
    	at io.outfoxx.swiftpoet.FileSpec.writeTo(FileSpec.kt:73)
    
    opened by PaulWoitaschek 2
  • Type bound is incorrectly generated in case of 2 or more bound types.

    Type bound is incorrectly generated in case of 2 or more bound types.

    Consider the following code

    TypeSpec
            .structBuilder("TestStruct")
            .addTypeVariable(
                TypeVariableName.typeVariable(
                    "T",
                    TypeVariableName.bound(Bound1),
                    TypeVariableName.bound(Bound2)
                ),
            )
            .build()
    

    the generated struct will be:

    struct TestStruct<T> where T : Bound1 where T : Bound2 {
    }
    

    but expected:

    struct TestStruct<T> where T : Bound1, T : Bound2 {
    }
    
    opened by alexanderbliznyuk 2
  • Remove requirement that enums have at least one case

    Remove requirement that enums have at least one case

    An enum with no cases is valid in Swift, and such a definition is sometimes useful to provide "namespacing", such as:

    enum Foo {
    	struct Bar {…}
    }
    
    opened by efirestone 2
  • Do not indent switch when used in beginControlFlow

    Do not indent switch when used in beginControlFlow

    If the string starts with "switch " then do not automatically indent. Downside: we would have to maintain a boolean stack of calls to beginControlFlow such that on symmetric calls to nextControlFlow/endControlFlow know whether or not to unindent. As a result, this may not be worth doing! And that's fine.

    This syntactical formatting oddity offends me, but apparently it's idiomatic. I just ported all my use of beginControlFlow for switch to addCode. I'm perfectly fine leaving it like that, but figured I'd file and see what others thought.

    enhancement 
    opened by JakeWharton 2
  • Preprocessor support

    Preprocessor support

    This is probably an insane feature to support fully, but perhaps we can distill targeted usage.

    My sole use case is wrapping an entire extension like:

    #if !FEATURE
    extension Foo : Bar {}
    #endif
    
    opened by JakeWharton 2
  • Cannot emit backticked property

    Cannot emit backticked property

    When trying to create the property, the name is first checked to be valid so ones like "extension" fail.

    https://github.com/outfoxx/swiftpoet/blob/9d7a1bbb90cb5eaf17d05ccf4297515d375caf19/src/main/java/io/outfoxx/swiftpoet/PropertySpec.kt#L167

    If I switch to manually backticking the name I get past this check but then upon emit it's has an additional set of backticks added to it.

    https://github.com/outfoxx/swiftpoet/blob/9d7a1bbb90cb5eaf17d05ccf4297515d375caf19/src/main/java/io/outfoxx/swiftpoet/PropertySpec.kt#L45

    This produces something like

    struct Foo {
      let ``extension``: String
    }
    

    It seems like one or the other behaviors need removed. Either a property allows all names and then escapes with backticks if necessary, or it still does validation on the way in and then does not escape when emitting.

    bug 
    opened by JakeWharton 2
  • Update Documentation

    Update Documentation

    • ~References to Kotlin files and other incorrect terminology need to be updated or removed.~
    • All classes need have at least basic documentation.
    • README should have more/better examples of Swift generation.
    bug 
    opened by kdubb 3
  • Consider emitting

    Consider emitting "MARK" comments between code sections

    Since the members of a class/struct/enum are emitted in a particular order, "MARK" comments could be produced between the sections to aid in navigation in xcode.

    Something like

    class Foo {
    
      // MARK Public Properties
    
      public var bar: Bar
    
      // MARK Private properties
    
      var baz: Baz
    
      // MARK Initializers
    
      ..
    
      // MARK Public functions
    
      ..
    
      // MARK Private functions
    
      ..
    }
    
    enhancement 
    opened by JakeWharton 0
Releases(v1.4.3)
  • v1.4.3(Jul 29, 2022)

  • v1.4.2(Jun 13, 2022)

  • v1.4.1(Jun 13, 2022)

    This release fixes issues only.

    Resolved Issues

    • Where clauses with associated type constraints (e.g. P.T == String) were output incorrectly.
    • Type variables with same type requirements are always output in a where clause.
    • Formatting of extension now includes proper whitespace.
    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(May 13, 2022)

    This release fixes an issue and adds a couple of missing features.

    New Features

    • Implicitly unwrapped optionals are now supported via TypeName.makeImplicit.
    • Weak/Unowned reference support has been added to PropertySpec using new WEAK and UNOWNED modifiers.
    • DeclaredTypeName can now be forced to always fully qualify the type name instead of relying on module imports.

    Resolved Issues

    • Top level members now assume the correct implicit access level.
    • Imports for extensions on externally defined types are now imported correctly.
    • Rules for nesting type aliases in protocols have been fixed.
    Source code(tar.gz)
    Source code(zip)
  • v1.3.1(Oct 29, 2021)

    This release adds new features for basic Swift Concurrency support and other bug fixes.

    New Features

    • TypeSpec.actorBuilder has been added to allow defining actor types.
    • FunctionSpec.async(Bool) has been added to allow defining async functions.

    Resolved Issues

    • TupleTypeName now correctly allows multiple unnamed types.

    Note: The unused Guava dependency has been removed from the package; it was leftover and has been unused for some time.

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Oct 28, 2021)

  • v1.2.0(Oct 21, 2021)

    This release adds new features and bug fixes

    New Features

    • FunctionSpec.operatorBuilder has been added to allow defining operator functions.
    • FunctionSpec.deinitializerBuilder has been added to allow defining deinit functions.
    • Missing ParameterSpec.addAttribute functions have been added to ParameterSpec.Builder.

    Resolved Issues

    • @escaping closure parameters can now be generated using ParameterSpec.addAttribute(AttributeSpec.ESCAPING).
    • FunctionTypeName signatures are now generated correctly (without names).
    • Generic types with multiple bounds are now generated correctly.
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Mar 12, 2021)

    1.1.0 is here and provides new features and bug fixes.

    New Features

    • NameAllocator brought over to allocate names avoiding collisions.
    • Taggable brought over to allow tagging generated objects with domain specific metadata.
    • nextControlFlow now has sensible defaults.
    • AnyTypeSpec.typeSpecs is now public (like other API properties).

    Resolved Issues

    • Fixed nextControlFlow extra spacing issue.
    • Remove incorrect limitation on generated Swift file names.

    Complete list of updates & fixes is here

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Aug 21, 2020)

    1.0.0 is here and provides new features, fixes and breaking changes.

    New Features

    • mutating and nonmutating modifiers are supported.
    • typealias's can be defined via TypeAliasSpec.
      • TypeAliasSpec be used anywhere a TypeSpec was previously allowed.
    • Enum cases allow documentation & attributes.
    • AttributeSpec accepts a DeclaredTypeName as the identifier for generating use of property wrappers.
    • #iif/#endif guards can be added to any FileSpec member.
    • FunctionSpec allows adding local type definitions that are emitted prior to general code.
    • Simple property get functions are emitted in concise format.

    Breaking Changes

    • addKDoc has been renamed to addDoc. Quite simpley, Swift documentation isn't referred to as KDoc.
    • beginControlFlow/nextControlFlow/endControlFlow requires the control flow construct be provided explicitly. The idiomatic Swift format (or at least the Xcode default) doesn't indent the cases of switches. Providing the control flow construct explicitly allows the code to be generated matching this format.

    Resolved Issues

    • Reserved property & enum case names are allowed and correctly escaped using backticks.
    • Reserved names are now correctly escaped using backticks.

    Complete list of updates & fixes is here

    Thanks

    Special thanks to @JakeWharton & @efirestone for their help on the library and this release!

    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Dec 18, 2019)

  • v0.2.0(Dec 18, 2019)

  • v0.1.0(Jul 11, 2018)

    The primary release has complete support generating:

    • Type (class/struct) Declarations
    • Enum Declarations
    • Protocol Declarations
    • Extension Declarations (with/without conditional conformances)
    • Function Declarations
    • Type Alias Declarations

    It also supports generating type names referring to:

    • Simple Types
    • Generic (e.g. Parameterized) Types
    • Tuple Types
    • Function Types

    Generating complex code blocks is easily done and includes automatic tracking of module imports and generating the most concise syntax possible.

    Source code(tar.gz)
    Source code(zip)
    swiftpoet-0.1.0-javadoc.jar(223.52 KB)
    swiftpoet-0.1.0-sources.jar(38.61 KB)
    swiftpoet-0.1.0.jar(161.98 KB)
Owner
Outfox
Outfox
An experimental UI toolkit for generating PowerPoint presentation files using Compose

ComposePPT An experimental UI toolkit for generating PowerPoint presentation files(.pptx) using Compose. Inspired by Glance and Mosaic. Why? This proj

Fatih Giriş 252 Dec 28, 2022
Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in Kotlin with Jetpack Compose and a backed in Kotlin hosted on AppEngine.

Conferences4Hall Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in K

Gérard Paligot 98 Dec 15, 2022
KmMScientists is a Kotlin multiplatform app with swift ui, jetpack compose, koin and realm

KmMScientists KmMScientists is a Kotlin multiplatform app built with swift ui, jetpack compose, koin and realm. Whats Shared? Local Data Persistence w

Kashif Mehmood 20 Dec 27, 2022
Library to use Kotlin Coroutines from Swift code in KMP apps

KMP-NativeCoroutines A library to use Kotlin Coroutines from Swift code in KMP apps. Flows Kotlin Create an extension property to expose the Flow as a

Rick Clephas 508 Jan 3, 2023
Functional Kotlin & Arrow based library for generating and verifying JWTs and JWSs

kJWT Functional Kotlin & Arrow based library for generating and verifying JWTs and JWSs. JWS JWT The following Algorithms are supported: HS256 HS384 H

Peter vR 31 Dec 25, 2022
Kotlin tooling for generating kotlinx.serialization serializers for serializing a class as a bitmask

kotlinx-serialization-bitmask Kotlin tooling for generating kotlinx.serialization serializers for serializing a class as a bitmask. Example @Serializa

marie 2 May 29, 2022
An android application for generating random quotes for learning Room, Jetpack Navigation and Lifecycles, Retrofit

Random-Quote-Generator An android application for generating random quotes for learning Room, Jetpack Navigation and Lifecycles, Retrofit MAD Score Te

Prasoon 2 Oct 16, 2022
Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders

Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Vehement 8 Nov 26, 2022
🛠️ The missing drawable toolbox for Android. Create drawables programmatically and get rid of the boring and always repeated drawable.xml files.

DrawableToolbox English | 中文 The missing DrawableToolbox for Android. Create drawables programmatically and get rid of the boring and always repeated

Hong Duan 1.1k Jan 4, 2023
Sync Kotlin files with an Xcode project

Kotlin Xcode Sync Note Soon to be deprecated. You can add folder references instead. See here. Import kotlin files into an Xcode project. This is used

null 25 May 20, 2022
Android project setup files when developing apps from scratch. The codebase uses lates jetpack libraries and MVVM repository architecture for setting up high performance apps

Android architecture app Includes the following Android Respository architecture MVVM Jepack libraries Carousel view Kotlin Kotlin Flow and Livedata P

null 2 Mar 31, 2022
This server uses json files to model items, entities and more.

Design Server | Simple server to design items, entities or more About this project/server: This server uses json files to model items, entities and mo

Phillipp Glanz 5 Jan 7, 2022
This program will read from your android application string.xml file and generate translated strings.xml files in your preferred languages using google sheet.

Localize your application content This program will read from your application string.xml file and generate translated strings.xml files in your prefe

DhiWise 4 Jul 29, 2022
Curations and configuration files for the OSS Review Toolkit.

ORT Config This repository contains configuration files for the OSS Review Toolkit. Content Curations The curations directory contains package curatio

OSS Review Toolkit 9 Dec 8, 2022
Astha Nayak 4 Oct 10, 2022
Open as default - A flutter plugin that allows setting up your flutter app to open files as default

open_as_default A flutter plugin that allows setting up your flutter app to open

LuisDeLaValier 3 Nov 15, 2022
SpyApp - The application launches dex files downloaded from the server

SpyApp The application downloads a dex file, which is then dynamically launched,

Vagiz Nasibullin 5 May 3, 2022
Uproot-JS - Extract JavaScript files from burp suite project with ease

Extract JavaScript files from burp suite project with ease. Disclaimer I am not

Dexter0us 50 Aug 8, 2022
API-Annotate - Single annotation to mark API elements

API-Annotate A single annotation for annotating externally-consumed elements in

null 0 Feb 5, 2022