-
Notifications
You must be signed in to change notification settings - Fork 247
Ability To Turn Off Formatting For Subdirectory #873
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
base: main
Are you sure you want to change the base?
Changes from all commits
eb29cb8
356b55f
021d6b3
3e4c5d2
8bade83
aac6fe8
a7d4c24
3046d92
bb4382e
17dc1bd
cf27a3c
7b22d51
fb8b06f
5d85e22
9ab91a5
7b35513
b2975de
ed1d3c4
3bc036e
cff2b22
e9861ca
ba343ca
c9a14e3
707061f
85840d6
5b5db57
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,109 @@ | ||||||||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||||||||
// | ||||||||||||||||||
// This source file is part of the Swift.org open source project | ||||||||||||||||||
// | ||||||||||||||||||
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors | ||||||||||||||||||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||||||||||||||||||
// | ||||||||||||||||||
// See https://swift.org/LICENSE.txt for license information | ||||||||||||||||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||||||||||||||||||
// | ||||||||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||||||||
|
||||||||||||||||||
import Foundation | ||||||||||||||||||
|
||||||||||||||||||
/// A file that describes which files and directories should be ignored by the formatter. | ||||||||||||||||||
/// In the future, this file may contain complex rules for ignoring files, based | ||||||||||||||||||
/// on pattern matching file paths. | ||||||||||||||||||
/// | ||||||||||||||||||
/// Currently, the only valid content for an ignore file is a single asterisk "*", | ||||||||||||||||||
/// optionally surrounded by whitespace. | ||||||||||||||||||
public class IgnoreFile { | ||||||||||||||||||
/// Name of the ignore file to look for. | ||||||||||||||||||
/// The presence of this file in a directory will cause the formatter | ||||||||||||||||||
/// to skip formatting files in that directory and its subdirectories. | ||||||||||||||||||
public static let standardFileName = ".swift-format-ignore" | ||||||||||||||||||
|
||||||||||||||||||
/// Errors that can be thrown by the IgnoreFile initializer. | ||||||||||||||||||
public enum Error: Swift.Error { | ||||||||||||||||||
/// Error thrown when initialising with invalid content. | ||||||||||||||||||
case invalidContent | ||||||||||||||||||
|
||||||||||||||||||
/// Error thrown when we fail to initialise with the given URL. | ||||||||||||||||||
case invalidFile(URL, Swift.Error) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Create an instance from a string. | ||||||||||||||||||
/// Returns nil if the content is not valid. | ||||||||||||||||||
public init(_ content: String) throws { | ||||||||||||||||||
guard content.trimmingCharacters(in: .whitespacesAndNewlines) == "*" else { | ||||||||||||||||||
throw Error.invalidContent | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Create an instance from the contents of the file at the given URL. | ||||||||||||||||||
/// Throws an error if the file content can't be read, or is not valid. | ||||||||||||||||||
public convenience init(contentsOf url: URL) throws { | ||||||||||||||||||
do { | ||||||||||||||||||
try self.init(try String(contentsOf: url, encoding: .utf8)) | ||||||||||||||||||
} catch { | ||||||||||||||||||
throw Error.invalidFile(url, error) | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Create an instance for the given directory, if a valid | ||||||||||||||||||
/// ignore file with the standard name is found in that directory. | ||||||||||||||||||
/// Returns nil if no ignore file is found. | ||||||||||||||||||
/// Throws an error if an invalid ignore file is found. | ||||||||||||||||||
/// | ||||||||||||||||||
/// Note that this initializer does not search parent directories for ignore files. | ||||||||||||||||||
public convenience init?(forDirectory directory: URL) throws { | ||||||||||||||||||
let url = directory.appendingPathComponent(IgnoreFile.standardFileName) | ||||||||||||||||||
|
||||||||||||||||||
do { | ||||||||||||||||||
try self.init(contentsOf: url) | ||||||||||||||||||
} catch { | ||||||||||||||||||
if case let Error.invalidFile(_, underlying) = error, (underlying as NSError).domain == NSCocoaErrorDomain, | ||||||||||||||||||
(underlying as NSError).code == NSFileReadNoSuchFileError | ||||||||||||||||||
{ | ||||||||||||||||||
return nil | ||||||||||||||||||
} | ||||||||||||||||||
throw error | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Create an instance to use for the given URL. | ||||||||||||||||||
/// We search for an ignore file starting from the given URL's container, | ||||||||||||||||||
/// and moving up the directory tree, until we reach the root directory. | ||||||||||||||||||
/// Returns nil if no ignore file is found. | ||||||||||||||||||
/// Throws an error if an invalid ignore file is found somewhere | ||||||||||||||||||
/// in the directory tree. | ||||||||||||||||||
/// | ||||||||||||||||||
/// Note that we start the search from the given URL's **container**, | ||||||||||||||||||
/// not the URL itself; the URL passed in is expected to be for a file. | ||||||||||||||||||
/// If you pass a directory URL, the search will not include the contents | ||||||||||||||||||
/// of that directory. | ||||||||||||||||||
public convenience init?(for url: URL) throws { | ||||||||||||||||||
guard !url.isRoot else { | ||||||||||||||||||
return nil | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
var containingDirectory = url.absoluteURL.standardized | ||||||||||||||||||
repeat { | ||||||||||||||||||
containingDirectory.deleteLastPathComponent() | ||||||||||||||||||
let url = containingDirectory.appendingPathComponent(IgnoreFile.standardFileName) | ||||||||||||||||||
if FileManager.default.isReadableFile(atPath: url.path) { | ||||||||||||||||||
try self.init(contentsOf: url) | ||||||||||||||||||
return | ||||||||||||||||||
} | ||||||||||||||||||
Comment on lines
+95
to
+98
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be able to skip this file system access and just check if
Suggested change
|
||||||||||||||||||
} while !containingDirectory.isRoot | ||||||||||||||||||
return nil | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Should the given URL be processed? | ||||||||||||||||||
/// Currently the only valid ignore file content is "*", | ||||||||||||||||||
/// which means that all files should be ignored. | ||||||||||||||||||
func shouldProcess(_ url: URL) -> Bool { | ||||||||||||||||||
return false | ||||||||||||||||||
} | ||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,7 +57,7 @@ public struct FileIterator: Sequence, IteratorProtocol { | |
/// - workingDirectory: `URL` that indicates the current working directory. Used for testing. | ||
public init(urls: [URL], followSymlinks: Bool, workingDirectory: URL = URL(fileURLWithPath: ".")) { | ||
self.workingDirectory = workingDirectory | ||
self.urls = urls | ||
self.urls = urls.filter(inputShouldBeProcessed(at:)) | ||
self.urlIterator = self.urls.makeIterator() | ||
self.followSymlinks = followSymlinks | ||
} | ||
|
@@ -92,6 +92,20 @@ public struct FileIterator: Sequence, IteratorProtocol { | |
fallthrough | ||
|
||
case .typeDirectory: | ||
do { | ||
if let ignoreFile = try IgnoreFile(forDirectory: next), !ignoreFile.shouldProcess(next) { | ||
// skip this directory and its subdirectories if it should be ignored | ||
continue | ||
} | ||
} catch IgnoreFile.Error.invalidFile(let url, _) { | ||
// we hit an invalid ignore file | ||
// we return the path of the ignore file so that we can report an error | ||
// and process the directory as normal | ||
output = url | ||
} catch { | ||
// we hit another unexpected error; process the directory as normal | ||
} | ||
Comment on lines
+100
to
+107
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to set |
||
|
||
dirIterator = FileManager.default.enumerator( | ||
at: next, | ||
includingPropertiesForKeys: nil, | ||
|
@@ -179,3 +193,34 @@ private func fileType(at url: URL) -> FileAttributeType? { | |
// Linux. | ||
return try? FileManager.default.attributesOfItem(atPath: url.path)[.type] as? FileAttributeType | ||
} | ||
|
||
/// Returns true if the file should be processed. | ||
/// Directories are always processed. | ||
/// For other files, we look for an ignore file in the containing | ||
/// directory or any of its parents. | ||
/// If there is no ignore file, we process the file. | ||
/// If an ignore file is found, we consult it to see if the file should be processed. | ||
/// An invalid ignore file is treated here as if it does not exist, but | ||
/// will be reported as an error when we try to process the directory. | ||
private func inputShouldBeProcessed(at url: URL) -> Bool { | ||
guard fileType(at: url) != .typeDirectory else { | ||
return true | ||
} | ||
|
||
let ignoreFile = try? IgnoreFile(for: url) | ||
return ignoreFile?.shouldProcess(url) ?? true | ||
} | ||
|
||
fileprivate extension URL { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we use |
||
var isRoot: Bool { | ||
#if os(Windows) | ||
// FIXME: We should call into Windows' native check to check if this path is a root once https://github.com/swiftlang/swift-foundation/issues/976 is fixed. | ||
// https://github.com/swiftlang/swift-format/issues/844 | ||
return self.pathComponents.count <= 1 | ||
#else | ||
// On Linux, we may end up with an string for the path due to https://github.com/swiftlang/swift-foundation/issues/980 | ||
// TODO: Remove the check for "" once https://github.com/swiftlang/swift-foundation/issues/980 is fixed. | ||
return self.path == "/" || self.path == "" | ||
#endif | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -165,6 +165,13 @@ class Frontend { | |
/// Read and prepare the file at the given path for processing, optionally synchronizing | ||
/// diagnostic output. | ||
private func openAndPrepareFile(at url: URL) -> FileToProcess? { | ||
guard url.lastPathComponent != IgnoreFile.standardFileName else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This way of reporting errors from invalid |
||
diagnosticsEngine.emitError( | ||
ahoppen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"Invalid ignore file \(url.relativePath): currently the only supported content for ignore files is a single asterisk `*`, which matches all files." | ||
) | ||
return nil | ||
} | ||
|
||
guard let sourceFile = try? FileHandle(forReadingFrom: url) else { | ||
diagnosticsEngine.emitError( | ||
"Unable to open \(url.relativePath): file is not readable or does not exist" | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,126 @@ | ||||||||||||||||||||||||||||||||||||||||||
@_spi(Internal) import SwiftFormat | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add a copyright header to this test file? |
||||||||||||||||||||||||||||||||||||||||||
import XCTest | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
final class IgnoreFileTests: XCTestCase { | ||||||||||||||||||||||||||||||||||||||||||
var testTreeURL: URL? | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
/// Description of a file or directory tree to create for testing. | ||||||||||||||||||||||||||||||||||||||||||
enum TestTree { | ||||||||||||||||||||||||||||||||||||||||||
case file(String, String) | ||||||||||||||||||||||||||||||||||||||||||
case directory(String, [TestTree]) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
override func tearDown() { | ||||||||||||||||||||||||||||||||||||||||||
// Clean up any test tree after each test. | ||||||||||||||||||||||||||||||||||||||||||
if let testTreeURL { | ||||||||||||||||||||||||||||||||||||||||||
// try? FileManager.default.removeItem(at: testTreeURL) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+13
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No longer needed? |
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
/// Make a temporary directory tree for testing. | ||||||||||||||||||||||||||||||||||||||||||
/// Returns the URL of the root directory. | ||||||||||||||||||||||||||||||||||||||||||
/// The tree will be cleaned up after the test. | ||||||||||||||||||||||||||||||||||||||||||
/// If a tree is already set up, it will be cleaned up first. | ||||||||||||||||||||||||||||||||||||||||||
func makeTempTree(_ tree: TestTree) throws -> URL { | ||||||||||||||||||||||||||||||||||||||||||
if let testTreeURL { | ||||||||||||||||||||||||||||||||||||||||||
try? FileManager.default.removeItem(at: testTreeURL) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
let tempDir = FileManager.default.temporaryDirectory | ||||||||||||||||||||||||||||||||||||||||||
let tempURL = tempDir.appendingPathComponent(UUID().uuidString) | ||||||||||||||||||||||||||||||||||||||||||
try FileManager.default.createDirectory(at: tempURL, withIntermediateDirectories: true) | ||||||||||||||||||||||||||||||||||||||||||
try writeTree(tree, to: tempURL) | ||||||||||||||||||||||||||||||||||||||||||
testTreeURL = tempURL | ||||||||||||||||||||||||||||||||||||||||||
return tempURL | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+24
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about making this a
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
/// Write a file or directory tree to the given root URL. | ||||||||||||||||||||||||||||||||||||||||||
func writeTree(_ tree: TestTree, to root: URL) throws { | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would make this private
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
switch tree { | ||||||||||||||||||||||||||||||||||||||||||
case let .file(name, contents): | ||||||||||||||||||||||||||||||||||||||||||
print("Writing file \(name) to \(root)") | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leftover debug output? |
||||||||||||||||||||||||||||||||||||||||||
try contents.write(to: root.appendingPathComponent(name), atomically: true, encoding: .utf8) | ||||||||||||||||||||||||||||||||||||||||||
case let .directory(name, children): | ||||||||||||||||||||||||||||||||||||||||||
let directory = root.appendingPathComponent(name) | ||||||||||||||||||||||||||||||||||||||||||
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) | ||||||||||||||||||||||||||||||||||||||||||
for child in children { | ||||||||||||||||||||||||||||||||||||||||||
try writeTree(child, to: directory) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
func testMissingIgnoreFile() throws { | ||||||||||||||||||||||||||||||||||||||||||
let url = URL(filePath: "/") | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertNil(try IgnoreFile(forDirectory: url)) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertNil(try IgnoreFile(for: url.appending(path: "file.swift"))) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
func testValidIgnoreFile() throws { | ||||||||||||||||||||||||||||||||||||||||||
let url = try makeTempTree(.file(IgnoreFile.standardFileName, "*")) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertNotNil(try IgnoreFile(forDirectory: url)) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertNotNil(try IgnoreFile(for: url.appending(path: "file.swift"))) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
func testInvalidIgnoreFile() throws { | ||||||||||||||||||||||||||||||||||||||||||
let url = try makeTempTree(.file(IgnoreFile.standardFileName, "this is an invalid pattern")) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertThrowsError(try IgnoreFile(forDirectory: url)) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertThrowsError(try IgnoreFile(for: url.appending(path: "file.swift"))) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
func testEmptyIgnoreFile() throws { | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertThrowsError(try IgnoreFile("")) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
func testNestedIgnoreFile() throws { | ||||||||||||||||||||||||||||||||||||||||||
let url = try makeTempTree(.file(IgnoreFile.standardFileName, "*")) | ||||||||||||||||||||||||||||||||||||||||||
let fileInSubdirectory = url.appendingPathComponent("subdirectory").appending(path: "file.swift") | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertNotNil(try IgnoreFile(for: fileInSubdirectory)) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
func testIterateWithIgnoreFile() throws { | ||||||||||||||||||||||||||||||||||||||||||
let url = try makeTempTree(.file(IgnoreFile.standardFileName, "*")) | ||||||||||||||||||||||||||||||||||||||||||
let iterator = FileIterator(urls: [url], followSymlinks: false) | ||||||||||||||||||||||||||||||||||||||||||
let files = Array(iterator) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertEqual(files.count, 0) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
func testIterateWithInvalidIgnoreFile() throws { | ||||||||||||||||||||||||||||||||||||||||||
let url = try makeTempTree(.file(IgnoreFile.standardFileName, "this file is invalid")) | ||||||||||||||||||||||||||||||||||||||||||
let iterator = FileIterator(urls: [url], followSymlinks: false) | ||||||||||||||||||||||||||||||||||||||||||
let files = Array(iterator) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertEqual(files.count, 1) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertTrue(files.first?.lastPathComponent == IgnoreFile.standardFileName) | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
func testIterateWithNestedIgnoreFile() throws { | ||||||||||||||||||||||||||||||||||||||||||
let url = try makeTempTree( | ||||||||||||||||||||||||||||||||||||||||||
.directory( | ||||||||||||||||||||||||||||||||||||||||||
"Source", | ||||||||||||||||||||||||||||||||||||||||||
[ | ||||||||||||||||||||||||||||||||||||||||||
.directory( | ||||||||||||||||||||||||||||||||||||||||||
"Ignored", | ||||||||||||||||||||||||||||||||||||||||||
[ | ||||||||||||||||||||||||||||||||||||||||||
.file(IgnoreFile.standardFileName, "*"), | ||||||||||||||||||||||||||||||||||||||||||
.file("file.swift", "contents"), | ||||||||||||||||||||||||||||||||||||||||||
] | ||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||
.directory( | ||||||||||||||||||||||||||||||||||||||||||
"Not Ignored", | ||||||||||||||||||||||||||||||||||||||||||
[ | ||||||||||||||||||||||||||||||||||||||||||
.file("file.swift", "contents") | ||||||||||||||||||||||||||||||||||||||||||
] | ||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||
] | ||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
XCTAssertNil(try IgnoreFile(forDirectory: url)) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertNil(try IgnoreFile(for: url.appending(path: "Source/file.swift"))) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertNotNil(try IgnoreFile(for: url.appending(path: "Source/Ignored/file.swift"))) | ||||||||||||||||||||||||||||||||||||||||||
let iterator = FileIterator(urls: [url], followSymlinks: false) | ||||||||||||||||||||||||||||||||||||||||||
let files = Array(iterator) | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
XCTAssertEqual(files.count, 1) | ||||||||||||||||||||||||||||||||||||||||||
XCTAssertEqual(files.first?.lastPathComponent, "file.swift") | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this file still needed? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to standardize the URL here? Say we have a directory structure like
Then, when running swift-format on
/LibB/Externals/LibA/LibA.swift
, I would expect formatting to be skipped because of/LibB/Externals/.swift-format-ignore
. But with the current logic, we would standardize/LibB/Externals/LibA/LibA.swift
to/LibA/LibA.swift
in here and thus not find the.swift-format-ignore
file.