Skip to content

Add breakLineAt End & Start OfScope rule #2029

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

amir-ardalanuk
Copy link

This pull request introduces a new formatting rule, breakLineAtEndOfTypes, to enforce a blank line before the closing brace of type declarations (e.g., class, struct, enum). It includes updates to the core formatting logic, configuration options, and test cases, as well as project file changes to integrate the new rule.

New Rule Implementation

  • Added a new rule, breakLineAtEndOfTypes, to ensure a blank line exists before the closing brace of type declarations. This rule supports types such as class, struct, enum, protocol, extension, and actor. (Sources/Rules/BreakLineAtEndOfTypes.swift)

Configuration and Options

  • Introduced a new breakLineAtEndOfTypes property in the FormatOptions struct to enable or disable the rule. Default value is false. (Sources/Options.swift) [1] [2] [3]
  • Added a corresponding OptionDescriptor for breakLineAtEndOfTypes to allow configuration through command-line arguments or configuration files. (Sources/OptionDescriptor.swift)

Testing

  • Added comprehensive test cases in BreakLineAtEndOfTypesTests.swift to validate the new rule against various scenarios, including classes, structs, enums, protocols, extensions, and actors. Tests also cover edge cases like preserving existing blank lines and handling disabled options. (Tests/Rules/BreakLineAtEndOfTypesTests.swift)

Project Integration

  • Updated the Xcode project file to include the new source file (BreakLineAtEndOfTypes.swift) and its corresponding test file (BreakLineAtEndOfTypesTests.swift). (SwiftFormat.xcodeproj/project.pbxproj) [1] [2] [3] [4] [5] [6] [7] [8] [9]
  • Added a new test scheme, SwiftFormatTests.xcscheme, to include the new test cases in the test suite. (SwiftFormat.xcodeproj/xcshareddata/xcschemes/SwiftFormatTests.xcscheme)

Minor Adjustments

  • Updated PerformanceTests to include the new rule in its configuration options for performance measurement. (PerformanceTests/PerformanceTests.swift)

@amir-ardalanuk amir-ardalanuk changed the title Add breakLineAtEndOfTypes rule [WIP] Add breakLineAtEndOfTypes rule May 6, 2025
Repository owner deleted a comment May 9, 2025
@amir-ardalanuk amir-ardalanuk force-pushed the Add-breakLineAtEndOfTypes-rule branch from 9e5558a to 6c28718 Compare May 12, 2025 07:38
@amir-ardalanuk amir-ardalanuk changed the title [WIP] Add breakLineAtEndOfTypes rule Add breakLineAt End & Start OfScope rule May 12, 2025
@amir-ardalanuk amir-ardalanuk requested a review from calda May 12, 2025 07:40
@@ -1047,3 +1046,9 @@ public struct Options {
fileOptions?.shouldSkipFile(inputURL) ?? false
}
}

public enum TypeBlankLines: String, CaseIterable {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please place this declaration next to the other declaration option types in this file

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A doc comment would be nice as well

"""
}
}

private extension Formatter {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be internal

// we need to modify the tokens
if linebreakCount != 2 || !hasWhitespaceAfterLastLinebreak {
// Remove existing whitespace and linebreaks
formatter.removeTokens(in: (lastContentIndex + 1) ..< endOfScopeIndex)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove tokens before adding tokens? One problem is that this will remove any comments that may be present at the end of the type.

I think it would be better to just insert a single line break at the end of the type if necessary.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this code could be simplified using the existing numberOfTrailingLinebreaks() helper defined on Array<Token>. You could do:

let typeBody = Array(formatter.tokens[startOfScope..<endOfScope])
let numberOfTrailingLinebreaks = typeBody.numberOfTrailingLinebreaks()

if numberOfTrailingLinebreaks != 2 {
  // insert linebreak at end of type
}

return
}
// Check if this is a type declaration
let isTypeDeclaration = ["class", "actor", "struct", "enum", "protocol", "extension"].contains(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this could use the Formatter.isTypeDeclaration helper that you factored out in the other file

formatter.removeTokens(in: indexOfFirstLineBreak ..< indexOfLastLineBreak)
}
case .insert, .preserve:
// We don't insert blank lines at start of scope, and preserve means do nothing
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding support for the .insert case here as well? 🙏🏻

@@ -930,7 +929,7 @@ public struct FormatOptions: CustomStringConvertible {
self.timeZone = timeZone
self.nilInit = nilInit
self.preservedPrivateDeclarations = preservedPrivateDeclarations
// Doesn't really belong here, but hard to put elsewhere
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please preserve this existing comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants