Skip to content

Commit

Permalink
Enum namespace rule (#737)
Browse files Browse the repository at this point in the history
  • Loading branch information
facumenzella authored and nicklockwood committed Sep 20, 2020
1 parent 337d787 commit dffcfec
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 11 deletions.
5 changes: 5 additions & 0 deletions Rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* [duplicateImports](#duplicateImports)
* [elseOnSameLine](#elseOnSameLine)
* [emptyBraces](#emptyBraces)
* [enumNamespaces](#enumNamespaces)
* [fileHeader](#fileHeader)
* [hoistPatternLet](#hoistPatternLet)
* [indent](#indent)
Expand Down Expand Up @@ -433,6 +434,10 @@ Remove whitespace inside empty braces.
</details>
<br/>

## enumNamespaces

Converts types used for hosting only static members into enums.

## fileHeader

Use specified source file header template for all files.
Expand Down
2 changes: 1 addition & 1 deletion Snapshots/Layout/Layout/LayoutConsole.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Foundation
import UIKit

/// Singleton for managing the Layout debug console interface
public struct LayoutConsole {
public enum LayoutConsole {
private static var errorView = LayoutErrorView()
private static var warningView = LayoutWarningView()

Expand Down
2 changes: 1 addition & 1 deletion Snapshots/Layout/Layout/LayoutManaged.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import Foundation

/// A protocol for view-type classes that can be configured using Layout
@objc protocol LayoutConfigurable: class {
@objc protocol LayoutConfigurable: enum {
/// Expression names and types
@objc static var expressionTypes: [String: RuntimeType] { get }
}
Expand Down
6 changes: 3 additions & 3 deletions Snapshots/Layout/Layout/Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,11 @@ struct UIntOptionSet: OptionSet {
#if !swift(>=4)

extension NSAttributedString {
struct DocumentType {
enum DocumentType {
static let html = NSHTMLTextDocumentType
}

struct DocumentReadingOptionKey {
enum DocumentReadingOptionKey {
static let documentType = NSDocumentTypeDocumentAttribute
static let characterEncoding = NSCharacterEncodingDocumentAttribute
}
Expand All @@ -169,7 +169,7 @@ struct UIntOptionSet: OptionSet {
}

extension UIFontDescriptor {
struct AttributeName {
enum AttributeName {
static let traits = UIFontDescriptorTraitsAttribute
}

Expand Down
61 changes: 61 additions & 0 deletions Sources/Rules.swift
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,67 @@ public struct _FormatRules {
}
}

// Converts types used for hosting only static members into enums to avoid instantiation.
public let enumNamespaces = FormatRule(
help: "Converts types used for hosting only static members into enums.",
options: []
) { formatter in
func rangeHostsOnlyStaticMembersAtTopLevel(start startIndex: Int, end endIndex: Int) -> Bool {
// exit for empty declarations
guard formatter.next(.nonSpaceOrCommentOrLinebreak, in: startIndex ..< endIndex) != nil else { return false }

var j = startIndex
while j < endIndex, let token = formatter.token(at: j) {
if token == .startOfScope("{"), let skip = formatter.index(of: .endOfScope,
after: j,
if: { $0 == .endOfScope("}") })
{
j = skip
continue
}
// exit if there's a explicit init
if token == .keyword("init") {
return false
} else if [.keyword("let"),
.keyword("var"),
.keyword("func")].contains(token),
!formatter.modifiersForType(at: j, contains: "static")
{
return false
}
j += 1
}
return true
}

formatter.forEachToken(where: { $0 == .keyword("class") || $0 == .keyword("struct") }) { i, _ in
guard formatter.last(.keyword, before: i) != .keyword("import") else { return }
// exit if class is a type modifier
guard let next = formatter.next(.nonSpaceOrCommentOrLinebreak, after: i), !next.isKeyword else { return }

// exit for class as protocol conformance
guard formatter.last(.nonSpaceOrCommentOrLinebreak, before: i) != .delimiter(":") else { return }

guard let braceIndex = formatter.index(after: i, where: { $0 == .startOfScope("{") }) else { return }

// exit if type is conforming any types
guard !formatter.tokens[i ... braceIndex].contains(.delimiter(":")) else { return }

guard let endIndex = formatter.index(after: braceIndex, where: { $0 == .endOfScope("}") }) else { return }

if rangeHostsOnlyStaticMembersAtTopLevel(start: braceIndex + 1, end: endIndex) {
formatter.replaceToken(at: i, with: [.keyword("enum")])

let start = formatter.startOfModifiers(at: i)
if formatter.modifiersForType(at: i, contains: "final"),
let finalIndex = formatter.lastIndex(in: start ..< i, where: { $0 == .identifier("final") })
{
formatter.removeTokens(in: finalIndex ... finalIndex + 1)
}
}
}
}

/// Remove trailing space from the end of lines, as it has no semantic
/// meaning and leads to noise in commits.
public let trailingSpace = FormatRule(
Expand Down
6 changes: 5 additions & 1 deletion Tests/RulesTests+Braces.swift
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,11 @@ extension RulesTests {
}
"""
let options = FormatOptions(allmanBraces: true)
testFormatting(for: input, output, rule: FormatRules.braces, options: options)
testFormatting(
for: input, output,
rule: FormatRules.braces,
options: options
)
}

func testAllmanBracesForInit() {
Expand Down
2 changes: 1 addition & 1 deletion Tests/RulesTests+Organization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ extension RulesTests {
testFormatting(
for: input, output,
rule: FormatRules.organizeDeclarations,
exclude: ["blankLinesAtStartOfScope"]
exclude: ["blankLinesAtStartOfScope", "enumNamespaces"]
)
}

Expand Down
6 changes: 3 additions & 3 deletions Tests/RulesTests+Redundancy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1425,7 +1425,7 @@ extension RulesTests {

func testNoRemoveBackticksAroundTypeInsideType() {
let input = "struct Foo {\n enum `Type` {}\n}"
testFormatting(for: input, rule: FormatRules.redundantBackticks)
testFormatting(for: input, rule: FormatRules.redundantBackticks, exclude: ["enumNamespaces"])
}

func testNoRemoveBackticksAroundLetArgument() {
Expand All @@ -1452,7 +1452,7 @@ extension RulesTests {

func testNoRemoveBackticksAroundTypePropertyInsideType() {
let input = "struct Foo {\n enum `Type` {}\n}"
testFormatting(for: input, rule: FormatRules.redundantBackticks)
testFormatting(for: input, rule: FormatRules.redundantBackticks, exclude: ["enumNamespaces"])
}

func testNoRemoveBackticksAroundTrueProperty() {
Expand Down Expand Up @@ -1855,7 +1855,7 @@ extension RulesTests {
func testRemoveSelfInStaticFunction() {
let input = "struct Foo {\n static func foo() {\n func bar() { self.foo() }\n }\n}"
let output = "struct Foo {\n static func foo() {\n func bar() { foo() }\n }\n}"
testFormatting(for: input, output, rule: FormatRules.redundantSelf)
testFormatting(for: input, output, rule: FormatRules.redundantSelf, exclude: ["enumNamespaces"])
}

func testRemoveSelfInClassFunctionWithModifiers() {
Expand Down
7 changes: 6 additions & 1 deletion Tests/RulesTests+Wrapping.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2229,7 +2229,12 @@ extension RulesTests {
class Foo {}
"""
let options = FormatOptions(typeAttributes: .prevLine)
testFormatting(for: input, output, rule: FormatRules.wrapAttributes, options: options)
testFormatting(
for: input,
output,
rule: FormatRules.wrapAttributes,
options: options
)
}

func testTypeAttributeStaysWrapped() {
Expand Down

0 comments on commit dffcfec

Please sign in to comment.