📝 SwiftRewriter

Swift 5.1 Build Status

使用 SwiftSyntax 的 Swift 代码格式化工具。

要求: Swift 5.1 (Xcode 11.0) + SwiftSyntax 0.50100.0

了解更多详情,请参阅我的 iOSConf SG 2019 演讲

概述

  1. SwiftRewriter: 可重用和可组合的 SyntaxRewriter 集合
  2. swift-rewriter: 简单的命令行可执行文件

如何使用

$ 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

配置

swift-rewriter 命令行工具中,重写规则在 rewriter.swift 中配置(目前不支持 yaml 或 json 等配置文件)。

请根据您的喜好更改配置(您可以创建自己的重写器并进行组合!),然后 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 示例

缩进器

更好的右大括号位置

@@ −1,6 +1,6 @@
 lets
     .code {
     }
     .format {
-} // this!!!
+    } // this!!!

附注:这是创建 SwiftRewriter 的主要目标。

首项感知缩进

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

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

将会变成

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

将会变成

import A
import B
import C
import D

func foo() {}

ExtensionIniter

此重写器移动代码以启用 struct成员逐一构造器

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 (正在进行中)

当代码过于密集时,此重写器会添加一个新行。

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()
        })
}

将会变成

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()
        })
}

路线图 / TODO

致谢

许可证

MIT