Git Product home page Git Product logo

swiftrewriter's Introduction

πŸ“ SwiftRewriter

Swift 5.1 Build Status

Swift code formatter using SwiftSyntax.

Requirements: Swift 5.1 (Xcode 11.0) + SwiftSyntax 0.50100.0

See also my iOSConf SG 2019 talk for more detail:

Overview

  1. SwiftRewriter: Collection of reusable & composable SyntaxRewriters
  2. swift-rewriter: Simple command-line executable

How to use

$ swift build
$ swift run swift-rewriter help

Available commands:

   help        Display general or command-specific help
   print-ast   print AST from file or string
   run         Auto-correct code in the file or directory

# Auto-correct code in the directory
$ swift run swift-rewriter run --path /path/to/file-or-directory

Configuration

In swift-rewriter CLI tool, rewriting rules are configured in rewriter.swift (configuration file e.g. yaml or json is not supported yet).

Please change the configuration as you like (you can make your own rewriter and combine!), and swift build & run.

// rewriter.swift

import SwiftRewriter

var rewriter: Rewriter {
    // Comment
    HeaderCopyrightTrimmer()

        // Move
        >>> ImportSorter()
//        >>> ExtensionIniter() // not useful for everyone

        // Token
        >>> DecimalLiteralUnderscorer()
        >>> SemicolonTrimmer()

        // Newline (whitespace)
//        >>> ExtraNewliner()   // not useful for everyone
        >>> ElseNewliner(newline: false)
        >>> MethodChainNewliner()

        // Indent (whitespace)
        >>> Indenter(.init(
            perIndent: .spaces(4),
            shouldIndentSwitchCase: false,
            shouldIndentIfConfig: false,
            skipsCommentedLine: true
            ))

        // Space (whitespace)
//        >>> ExtraSpaceTrimmer()   // may disturb manually-aligned code

        >>> ColonSpacer(spaceBefore: false, spaceAfter: true)
        >>> TernaryExprSpacer()
        >>> BinaryOperatorSpacer(spacesAround: true)

        // Ignore to not distrub user-aligned multiple assignments
        // TODO: Improve multiple assignment alignment
//        >>> EqualSpacer(spacesAround: true)

        >>> ArrowSpacer(spaceBefore: true, spaceAfter: true)
        >>> LeftBraceSpacer(spaceBefore: true)
        >>> LeftParenSpacer(spaceBefore: true)
        >>> TrailingSpaceTrimmer()
}

Rewriter examples

Indenter

Better right-brace position

@@ βˆ’1,6 +1,6 @@
 lets
     .code {
     }
     .format {
-} // this!!!
+    } // this!!!

P.S. This is the primary goal of making SwiftRewriter.

First-item-aware indent

    struct Foo {
                         init(bool: Bool,
              int: Int) {
                              self.bool = bool
                           if true {
                     print()
                  }

                   run { x in
                            print(x,
                                      y,
                                          z)
                }
                        }
            }

will be:

struct Foo {
    init(bool: Bool,
         int: Int) {
        self.bool = bool
        if true {
            print()
        }

        run { x in
            print(x,
                  y,
                  z)
        }
    }
}

HeaderCopyrightTrimmer

@@ βˆ’1,10 +1,2 @@
-//
-//  example.swift
-//  SwiftRewriter
-//
-//  Created by Yasuhiro Inami on 2018-12-09.
-//  Copyright Β© 2018 Yasuhiro Inami. All rights reserved.
-//
-
 // All your code are belong to us.

ImportSorter

import C
import B

func foo() {}

import A
import D

will be:

import A
import B
import C
import D

func foo() {}

ExtensionIniter

This rewriter moves the code to enable struct's memberwise initializer.

struct Foo {
    let int: Int
    init(int: Int) {
        self.int = int
    }
    init() {
        self.int = 0
    }
}
@@ βˆ’1,9 +1,12 @@
 struct Foo {
     let int: Int
+}
+
+extension Foo {
     init(int: Int) {
         self.int = int
     }
     init() {
         self.int = 0
     }
 }

ExtraNewliner (Work in Progress)

This rewriter adds a newline when code is too dense.

import Foundation
var computed1: Int = 1
var computed2: Int = { return 2 }
/// doc
var computed3: Int = { return 3 }
/// doc
var computedBlock: String {
    return ""
}
func send() -> Observable<Void> {
    return apiSession
        .send(request)
        .do(onError: { [weak self] error in
            guard let me = self else { return }
            me.doSomething()
        })
        .do(onError: { [weak self] error in
            guard let me = self else { return }
            me.doSomething()
            me.doSomething()
        })
}

will be:

import Foundation

var computed1: Int = 1
var computed2: Int = { return 2 }

/// doc
var computed3: Int = { return 3 }

/// doc
var computedBlock: String {
    return ""
}

func send() -> Observable<Void> {
    return apiSession
        .send(request)
        .do(onError: { [weak self] error in
            guard let me = self else { return }
            me.doSomething()
        })
        .do(onError: { [weak self] error in
            guard let me = self else { return }

            me.doSomething()
            me.doSomething()
        })
}

Roadmap / TODO

  • Add configuration file support
  • Automatic code folding
  • Move properties above method (for "states" readability)
  • Move inner types to extension scope (for "states" readability)
  • Align multiline = assignments
  • (Your idea comes here πŸ’‘)

Acknowledgement

License

MIT

swiftrewriter's People

Contributors

inamiy avatar mbrandonw avatar roslund avatar suryakantsharma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swiftrewriter's Issues

Too many open files

I ran the script on my entire XCode project. Perhaps a poor choice admittedly.
swift run swift-rewriter run --path ~/Developer/magma/ios/magma/

Now I am stuck, as my computer keeps complaining about too many open files

warning: could not open directory 'Tests/SwiftRewriterTests/Comment/': Too many open files warning: could not open directory 'Tests/SwiftRewriterTests/Newline/': Too many open files warning: could not open directory 'Tests/SwiftRewriterTests/Combined/': Too many open files warning: could not open directory 'Tests/SwiftRewriterTests/Space/': Too many open files warning: could not open directory 'Tests/SwiftRewriterTests/Helpers/': Too many open files warning: unable to access 'Sources/swift-rewriter/.gitignore': Too many open files warning: could not open directory 'Sources/swift-rewriter/Utilities/': Too many open files warning: could not open directory 'Sources/swift-rewriter/Commands/': Too many open files warning: unable to access 'Sources/SwiftRewriter/.gitignore': Too many open files warning: could not open directory 'Sources/SwiftRewriter/Types/': Too many open files warning: could not open directory 'Sources/SwiftRewriter/Extensions/': Too many open files warning: could not open directory 'Sources/SwiftRewriter/Utilities/': Too many open files warning: could not open directory 'Sources/SwiftRewriter/Rewriters/': Too many open files warning: could not open directory 'Sources/SwiftRewriter/Protocols/': Too many open files warning: could not open directory 'Sources/SwiftRewriter/Debug/': Too many open files

Any ideas on what the culprit might be. Also, how do I close all these open files?

SwiftSyntax parser library isn't compatible

Hi
The code can be compiled in Linux but can't run on the canonic Hello project from Swift.
This error on the execution of
swift run swift-rewriter run --path /home/louis/DEV/Swift/SwiftRewriter/
give:
'SwiftSyntax parser library isn't compatible'

Ubuntu 20.04
Swift 5.3

Is it supposed to be compatible with Linux ?
Thank you

Multiline function header closing should be dedented one level

The rewriter currently transforms ...

func add(
    first: Int,
    second: Int,
    third: Int
) -> Int {
    return first + second + third
}

... into ...

func add(
    first: Int,
    second: Int,
    third: Int
    ) -> Int {
    return first + second + third
}

This, in my opinion, is less readable and currently keeps me from using the rewriter.

Incorrect indentation of for loop with case pattern match

Given:

enum Foo {
    case P(x: Int)
}
class A {
    func a() -> Bool {
        return true
    }
}

func foo() {
    for
      case let .P(x) in [Foo.P(x: 1)]
      where
        A()
          .a() {
        print(x)
    }
    for
      case let .P(x) in [Foo.P(x: 1)]
      where
        A()
          .a() {
        print(x)
    }
}

Output:

enum Foo {
    case P(x: Int)
}
class A {
    func a() -> Bool {
        return true
    }
}

func foo() {
    for
    case let .P(x) in [Foo.P(x: 1)]
        where
        A()
            .a() {
            print(x)
        }
        for
        case let .P(x) in [Foo.P(x: 1)]
            where
            A()
                .a() {
                print(x)
            }
        }

Incorrect indentation of switch with pattern matching

Given:

enum Foo {
    case P(x: Int)
}
class A {
    func a() -> Bool {
        return true
    }
}

func foo() {
    switch Foo.P(x: 1) {
    case .P(1)
    where
      A()
        .a():
        print(1)
    case .P(let 2)
           where
             A()
               .a():
        print(2)
    case _:
        print("other")
    }
}

Output:

enum Foo {
    case P(x: Int)
}
class A {
    func a() -> Bool {
        return true
    }
}

func foo() {
    switch Foo.P(x: 1) {
    case .P(1)
        where
        A()
            .a():
            print(1)
        case .P(let 2)
            where
            A()
                .a():
                print(2)
            case _:
                print("other")
            }
        }

Add "newline then infix-operator" rule

Examples

-let foo = veryLongBooleanFlag1 &&
-    veryLongBooleanFlag2
+let foo = veryLongBooleanFlag1
+    && veryLongBooleanFlag2
-let foo = flag ?
-     that
+let foo = flag
+    ? this
     : that
-let foo = curry(self.init) <^>
-     arg1 <*>
-     arg2 <*>
-     arg3
+let foo = curry(self.init)
+    <^> arg1
+    <*> arg2
+    <*> arg3

[Idea] Add `StructToEnumRewriter`

Change struct to enum whenever possible that doesn't require Foo.init().

Example

-struct Foo {
+enum Foo {
     static let bar = Bar()
 }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.