|
10 | 10 | //
|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
| 13 | +import Foundation |
| 14 | + |
13 | 15 | public enum TriviaPosition {
|
14 | 16 | case leading
|
15 | 17 | case trailing
|
@@ -43,65 +45,77 @@ public struct Trivia: Sendable {
|
43 | 45 | }
|
44 | 46 |
|
45 | 47 | /// The string contents of all the comment pieces with any comments tokens trimmed.
|
46 |
| - /// |
47 |
| - /// Each element in the array is the trimmed contents of a line comment, or, in the case of a multi-line comment a trimmed, concatenated single string. |
48 |
| - public var commentValues: [String] { |
| 48 | + public var commentValue: String { |
49 | 49 | var comments = [String]()
|
50 |
| - var partialComments = [String]() |
51 |
| - |
52 |
| - var foundStartOfCodeBlock = false |
53 |
| - var foundEndOfCodeBlock = false |
54 |
| - var isInCodeBlock: Bool { foundStartOfCodeBlock && !foundEndOfCodeBlock } |
55 | 50 |
|
56 |
| - for piece in pieces { |
57 |
| - switch piece { |
58 |
| - case .blockComment(let text), .docBlockComment(let text): |
59 |
| - let text = text.trimmingCharacters(in: "\n") |
| 51 | + // Determine if all line comments have a single space |
| 52 | + let allLineCommentsHaveSpace = pieces.allSatisfy { piece in |
| 53 | + guard case .lineComment(let text) = piece else { return true } |
| 54 | + return text.hasPrefix("// ") |
| 55 | + } |
60 | 56 |
|
61 |
| - foundStartOfCodeBlock = text.hasPrefix("/*") |
62 |
| - foundEndOfCodeBlock = text.hasSuffix("*/") |
| 57 | + // Determine if all doc line comments have a single space |
| 58 | + let allDocLineCommentsHaveSpace = pieces.allSatisfy { piece in |
| 59 | + guard case .docLineComment(let text) = piece else { return true } |
| 60 | + return text.hasPrefix("/// ") |
| 61 | + } |
63 | 62 |
|
64 |
| - let sanitized = |
65 |
| - text |
66 |
| - .split(separator: "\n") |
67 |
| - .map { $0.trimmingAnyCharacters(in: "/*").trimmingAnyCharacters(in: " ") } |
68 |
| - .filter { !$0.isEmpty } |
69 |
| - .joined(separator: " ") |
| 63 | + // Helper function to process block comments |
| 64 | + func processBlockComment(_ text: String, prefix: String, suffix: String) -> String { |
| 65 | + var text = text |
| 66 | + text.removeFirst(prefix.count) |
| 67 | + text.removeLast(suffix.count) |
| 68 | + text = text.trimmingCharacters(in: .whitespaces) |
| 69 | + let newlineCharacterSet = CharacterSet(charactersIn: "\n") |
| 70 | + return text.trimmingCharacters(in: newlineCharacterSet) |
| 71 | + } |
70 | 72 |
|
71 |
| - appendPartialCommentIfPossible(sanitized) |
| 73 | + // Helper function to process multiline block comments |
| 74 | + func processMultilineBlockComment(_ text: String) -> String { |
| 75 | + var lines = text.components(separatedBy: .newlines) |
72 | 76 |
|
73 |
| - case .lineComment(let text), .docLineComment(let text): |
74 |
| - if isInCodeBlock { |
75 |
| - appendPartialCommentIfPossible(text) |
76 |
| - } else { |
77 |
| - comments.append(String(text.trimmingPrefix("/ "))) |
78 |
| - } |
| 77 | + let lastLine = lines.last ?? "" |
| 78 | + let leadingSpaces = lastLine.prefix { $0 == " " }.count |
79 | 79 |
|
80 |
| - default: |
81 |
| - break |
82 |
| - } |
| 80 | + lines.removeFirst() |
| 81 | + lines.removeLast() |
83 | 82 |
|
84 |
| - if foundEndOfCodeBlock, !partialComments.isEmpty { |
85 |
| - appendSubstringsToLines() |
86 |
| - partialComments.removeAll() |
| 83 | + let processedLines = lines.map { line in |
| 84 | + String(line.dropFirst(leadingSpaces)) |
87 | 85 | }
|
88 |
| - } |
89 | 86 |
|
90 |
| - if !partialComments.isEmpty { |
91 |
| - appendSubstringsToLines() |
| 87 | + return processedLines.joined(separator: "\n") |
92 | 88 | }
|
93 | 89 |
|
94 |
| - func appendPartialCommentIfPossible(_ text: String) { |
95 |
| - guard partialComments.isEmpty || !text.isEmpty else { return } |
96 |
| - |
97 |
| - partialComments.append(text) |
98 |
| - } |
| 90 | + for piece in pieces { |
| 91 | + switch piece { |
| 92 | + case .blockComment(let text): |
| 93 | + let processedText = |
| 94 | + text.hasPrefix("/*\n") |
| 95 | + ? processMultilineBlockComment(text) |
| 96 | + : processBlockComment(text, prefix: "/*", suffix: "*/") |
| 97 | + comments.append(processedText) |
| 98 | + |
| 99 | + case .docBlockComment(let text): |
| 100 | + let processedText = |
| 101 | + text.hasPrefix("/**\n") |
| 102 | + ? processMultilineBlockComment(text) |
| 103 | + : processBlockComment(text, prefix: "/**", suffix: "*/") |
| 104 | + comments.append(processedText) |
| 105 | + |
| 106 | + case .lineComment(let text): |
| 107 | + let prefix = allLineCommentsHaveSpace ? "// " : "//" |
| 108 | + comments.append(String(text.dropFirst(prefix.count))) |
| 109 | + |
| 110 | + case .docLineComment(let text): |
| 111 | + let prefix = allDocLineCommentsHaveSpace ? "/// " : "///" |
| 112 | + comments.append(String(text.dropFirst(prefix.count))) |
99 | 113 |
|
100 |
| - func appendSubstringsToLines() { |
101 |
| - comments.append(partialComments.joined(separator: " ")) |
| 114 | + default: |
| 115 | + break |
| 116 | + } |
102 | 117 | }
|
103 |
| - |
104 |
| - return comments |
| 118 | + return comments.joined(separator: "\n") |
105 | 119 | }
|
106 | 120 |
|
107 | 121 | /// The length of all the pieces in this ``Trivia``.
|
|
0 commit comments