diff --git a/Changelog.md b/Changelog.md index 56ae57d1..59ebf126 100644 --- a/Changelog.md +++ b/Changelog.md @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 #159 by @mattt. - Fixed relationship diagram to prevent linking to unknown symbols. #178 by @MattKiazyk. +- Fixed problems in CommonMark output related to escaping emoji shortcode. + #167 by @mattt. ### Changed @@ -56,9 +58,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 #130 by @mattt. - Fixed file and directory unexpected permissions. #146 by @niw. -- Fixed rendering of colon sequences in function signatures - as emoji shortcodes (e.g. `:on:` → 🔛). - #149 by @mattt. - Fixed declarations for properties without explicit type annotations. #150 by @mattt. - Fixed visual regression for adjacent linked tokens in code block. diff --git a/Sources/swift-doc/Extensions/StringProtocol+Extensions.swift b/Sources/swift-doc/Extensions/StringProtocol+Extensions.swift new file mode 100644 index 00000000..b3d8a373 --- /dev/null +++ b/Sources/swift-doc/Extensions/StringProtocol+Extensions.swift @@ -0,0 +1,23 @@ +extension StringProtocol { + func indented(by spaces: Int = 2) -> String { + return String(repeating: " ", count: spaces) + self + } + + func leftPadded(to length: Int) -> String { + guard count < length else { return String(self) } + return String(repeating: " ", count: length - count) + self + } + + func rightPadded(to length: Int) -> String { + guard count < length else { return String(self) } + return self + String(repeating: " ", count: length - count) + } + + var escapingEmojiShortcodes: String { + // Insert U+200B ZERO WIDTH SPACE + // to prevent colon sequences from being interpreted as + // emoji shortcodes (without wrapping with code element). + // See: https://docs.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax#using-emoji + return self.replacingOccurrences(of: ":", with: ":\u{200B}") + } +} diff --git a/Sources/swift-doc/Subcommands/Coverage.swift b/Sources/swift-doc/Subcommands/Coverage.swift index 4fbf4d7c..b26d5a40 100644 --- a/Sources/swift-doc/Subcommands/Coverage.swift +++ b/Sources/swift-doc/Subcommands/Coverage.swift @@ -28,9 +28,9 @@ extension SwiftDoc { let data = try encoder.encode(report) try data.write(to: URL(fileURLWithPath: output)) } else { - print(["Total".rightPadded(to: 60), format(report.totals.percentage)].joined(separator: "\t")) + print(["Total".rightPadded(to: 60), format(percentage: report.totals.percentage)].joined(separator: "\t")) for (file, ratio) in report.coverageBySourceFile.sorted(by: { $0.0 < $1.0 }) { - print([" - \(file)".rightPadded(to: 60), format(ratio.percentage)].joined(separator: "\t")) + print([" - \(file)".rightPadded(to: 60), format(percentage: ratio.percentage)].joined(separator: "\t")) } print("") @@ -46,18 +46,6 @@ extension SwiftDoc { // MARK: - -fileprivate extension String { - func leftPadded(to length: Int) -> String { - guard count < length else { return self } - return String(repeating: " ", count: length - count) + self - } - - func rightPadded(to length: Int) -> String { - guard count < length else { return self } - return self + String(repeating: " ", count: length - count) - } -} - -fileprivate func format(_ percentage: Double) -> String { +fileprivate func format(percentage: Double) -> String { return String(format: "%0.2f %%", percentage).leftPadded(to: 8) } diff --git a/Sources/swift-doc/Subcommands/Diagram.swift b/Sources/swift-doc/Subcommands/Diagram.swift index 50c72443..4986df23 100644 --- a/Sources/swift-doc/Subcommands/Diagram.swift +++ b/Sources/swift-doc/Subcommands/Diagram.swift @@ -79,11 +79,3 @@ fileprivate func diagram(of module: Module) -> String { return dot } - -// MARK: - - -fileprivate extension String { - func indented(by spaces: Int = 2) -> String { - return String(repeating: " ", count: spaces) + self - } -} diff --git a/Sources/swift-doc/Supporting Types/Components/Abstract.swift b/Sources/swift-doc/Supporting Types/Components/Abstract.swift index e09454e8..0e2e1527 100644 --- a/Sources/swift-doc/Supporting Types/Components/Abstract.swift +++ b/Sources/swift-doc/Supporting Types/Components/Abstract.swift @@ -21,7 +21,7 @@ struct Abstract: Component { List.Item { Fragment { #""" - [\#(symbol.id)](\#(path(for: symbol, with: baseURL))): + [\#(symbol.id.description.escapingEmojiShortcodes)](\#(path(for: symbol, with: baseURL))): \#(summary) """# } @@ -31,7 +31,7 @@ struct Abstract: Component { return Fragment { List.Item { Paragraph { - Link(urlString: path(for: symbol, with: baseURL), text: symbol.id.description) + Link(urlString: path(for: symbol, with: baseURL), text: symbol.id.description.escapingEmojiShortcodes) } } } diff --git a/Sources/swift-doc/Supporting Types/Components/Documentation.swift b/Sources/swift-doc/Supporting Types/Components/Documentation.swift index ad96e1aa..96bfa686 100644 --- a/Sources/swift-doc/Supporting Types/Components/Documentation.swift +++ b/Sources/swift-doc/Supporting Types/Components/Documentation.swift @@ -36,7 +36,7 @@ struct Documentation: Component { } if documentation.summary != nil { - Fragment { "\(documentation.summary!)" } + Fragment { "\(documentation.summary!.escapingEmojiShortcodes)" } } Declaration(of: symbol, in: module, baseURL: baseURL) @@ -57,14 +57,14 @@ struct Documentation: Component { if documentation.throws != nil { Section { Heading { "Throws" } - Fragment { documentation.throws! } + Fragment { documentation.throws!.escapingEmojiShortcodes } } } if documentation.returns != nil { Section { Heading { "Returns" } - Fragment { documentation.returns! } + Fragment { documentation.returns!.escapingEmojiShortcodes } } } diff --git a/Sources/swift-doc/Supporting Types/Components/Requirements.swift b/Sources/swift-doc/Supporting Types/Components/Requirements.swift index afd8cff8..d7bf8eca 100644 --- a/Sources/swift-doc/Supporting Types/Components/Requirements.swift +++ b/Sources/swift-doc/Supporting Types/Components/Requirements.swift @@ -31,9 +31,11 @@ struct Requirements: Component { ForEach(in: sections) { section -> BlockConvertible in Section { Heading { section.title } - ForEach(in: section.requirements) { requirement in - Heading { requirement.name } - Documentation(for: requirement, in: module, baseURL: baseURL) + Section { + ForEach(in: section.requirements) { requirement in + Heading { requirement.name.escapingEmojiShortcodes } + Documentation(for: requirement, in: module, baseURL: baseURL) + } } } } diff --git a/Sources/swift-doc/Supporting Types/Page.swift b/Sources/swift-doc/Supporting Types/Page.swift index 29ba9da3..7e4886c2 100644 --- a/Sources/swift-doc/Supporting Types/Page.swift +++ b/Sources/swift-doc/Supporting Types/Page.swift @@ -24,13 +24,7 @@ extension Page { let data: Data? switch format { case .commonmark: - var text = document.render(format: .commonmark) - // Insert U+200B ZERO WIDTH SPACE - // to prevent colon sequences from being interpreted as - // emoji shortcodes (without wrapping with code element). - // See: https://docs.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax#using-emoji - text = text.replacingOccurrences(of: ":", with: ":\u{200B}") - data = text.data(using: .utf8) + data = document.render(format: .commonmark).data(using: .utf8) case .html: data = layout(self).description.data(using: .utf8) }