Skip to content

Commit

Permalink
Merge pull request #45 from YOCKOW/development
Browse files Browse the repository at this point in the history
Put out HTML as well.
  • Loading branch information
YOCKOW committed Jun 19, 2023
2 parents ae5a049 + c1cca9e commit f0326c7
Show file tree
Hide file tree
Showing 13 changed files with 367 additions and 53 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ jobs:
matrix:
os:
- ubuntu-22.04
- macOS-12
- macOS-13
swift-version:
- '5.8'
- '5.8.1'
swift-compat-ver:
- '5'
# - '4.2'
Expand All @@ -35,9 +35,10 @@ jobs:
uses: actions/cache@v3
with:
path: .build
key: build-${{ github.workspace }}-${{ runner.os }}-${{ matrix.swift-compat-ver }}-${{ hashFiles('**/*.swift') }}
key: build-${{ github.workspace }}-${{ runner.os }}-${{ matrix.swift-version }}-${{ matrix.swift-compat-ver }}-${{ hashFiles('**/*.swift') }}
restore-keys: |
build-${{ github.workspace }}-${{ runner.os }}-${{ matrix.swift-compat-ver }}-
build-${{ github.workspace }}-${{ runner.os }}-${{ matrix.swift-version }}-${{ matrix.swift-compat-ver }}-
build-${{ github.workspace }}-${{ runner.os }}-${{ matrix.swift-version }}-
build-${{ github.workspace }}-${{ runner.os }}-
build-${{ github.workspace }}-
- uses: YOCKOW/Action-setup-swift@main
Expand Down
59 changes: 48 additions & 11 deletions Sources/XHTML/Attributes.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* *************************************************************************************************
Attributes.swift
© 2018-2019 YOCKOW.
© 2018-2019,2023 YOCKOW.
Licensed under MIT License.
See "LICENSE.txt" for more information.
************************************************************************************************ */
Expand Down Expand Up @@ -33,39 +33,76 @@ extension Attributes {
private func _pairDescription(name: AttributeName, value: String) -> String {
return "\(name.description)=\"\(value._addingAmpersandEncoding())\""
}

private func _htmlPairDescription(name: AttributeName, value: String) -> String? {
switch name {
case .namespaceDeclaration:
if value == ._xhtmlNamespace {
return nil
}
return "\(name.description)=\"\(value._addingAmpersandEncoding())\""
case .attributeName(let attrName):
if attrName.prefix == .namespace("xml") { // hmm...
return nil
}
if _namespace(for: attrName) == ._xhtmlNamespace {
return "\(attrName.localName.description)=\"\(value._addingAmpersandEncoding())\""
}
return "\(attrName.description)=\"\(value._addingAmpersandEncoding())\""
}
}

public var xhtmlString: String {
return self._attributes.sorted(by: { $0.key < $1.key }).map({ _pairDescription(name: $0, value: $1) }).joined(separator: " ")
}

/// Lines containing attributes represented by XHTML.
/// The result is empty when the instance is empty.
public var prettyXHTMLLines: StringLines {

public var htmlString: String {
return _attributes.compactMap({ _htmlPairDescription(name: $0, value: $1) }).joined(separator: " ")
}

private func _prettyLines(html: Bool) -> StringLines {
var result = StringLines()
var buffer = ""

func _flush() {
result.append(String.Line(buffer)!)
buffer = ""
}

for (name, value) in self._attributes.sorted(by: { $0.key < $1.key }) {
let pairDescription = _pairDescription(name: name, value: value)
let pairDescription = html ? (_htmlPairDescription(name: name, value: value) ?? "") : _pairDescription(name: name, value: value)
if buffer.estimatedWidth + pairDescription.estimatedWidth > 100 {
_flush()
}
buffer += buffer.isEmpty ? pairDescription : " \(pairDescription)"
buffer += buffer.isEmpty || pairDescription.isEmpty ? pairDescription : " \(pairDescription)"
}

if !buffer.isEmpty { _flush() }

return result
}

/// Lines containing attributes represented by XHTML.
/// The result is empty when the instance is empty.
public var prettyXHTMLLines: StringLines {
return _prettyLines(html: false)
}

public var prettyHTMLLines: StringLines {
return _prettyLines(html: true)
}

public func prettyXHTMLString(indent: String.Indent = .default,
newline: Character.Newline = .lineFeed) -> String {
return self.prettyXHTMLLines._description(indent: indent, newline: newline)
}

public func prettyHTMLString(
indent: String.Indent = .default,
newline: Character.Newline = .lineFeed
)-> String {
return prettyHTMLLines._description(indent: indent, newline: newline)
}
}

extension Attributes {
Expand Down
71 changes: 67 additions & 4 deletions Sources/XHTML/Document.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,18 @@ open class Document {
}

private var _documentType: String {
guard let doctype = self.version._documentType else {
fatalError("The version of XHTML must be specified.")
}
return doctype
return self.version._documentType
}

public var xhtmlString: String {
return "\(self._xmlDeclaration)\n\(self._documentType)\n\(self.miscellanies.xhtmlString)"
}

public var htmlString: String {
get throws {
return "\(_documentType)\n\(try miscellanies.htmlString)"
}
}

public var prettyXHTMLLines: StringLines {
var result = StringLines([
Expand All @@ -66,6 +69,16 @@ open class Document {
result.append(contentsOf: self.miscellanies.prettyXHTMLLines)
return result
}

public var prettyHTMLLines: StringLines {
get throws {
var result = StringLines([
"\(self._documentType)",
])
result.append(contentsOf: try miscellanies.prettyHTMLLines)
return result
}
}

public func prettyXHTMLString(indent: String.Indent = .default,
newline: Character.Newline = .lineFeed) -> String {
Expand All @@ -74,6 +87,16 @@ open class Document {
lines.newline = newline
return lines.description
}

public func prettyHTMLString(
indent: String.Indent = .default,
newline: Character.Newline = .lineFeed
) throws -> String {
var lines = try prettyHTMLLines
lines.indent = indent
lines.newline = newline
return lines.description
}
}

open var prolog: Prolog
Expand Down Expand Up @@ -139,30 +162,70 @@ extension Document {
public var xhtmlString: String {
return self.prolog.xhtmlString + self.rootElement.xhtmlString + self.miscellanies.xhtmlString
}

public var htmlString: String {
get throws {
return try prolog.htmlString + rootElement.htmlString + miscellanies.htmlString
}
}

public var xhtmlData: Data? {
return self.xhtmlString.data(using:self.prolog.stringEncoding)
}

public var htmlData: Data? {
get throws {
return try htmlString.data(using: prolog.stringEncoding)
}
}

public var prettyXHTMLLines: StringLines {
var result = self.prolog.prettyXHTMLLines
result.append(contentsOf: self.rootElement.prettyXHTMLLines)
result.append(contentsOf: self.miscellanies.prettyXHTMLLines)
return result
}

public var prettyHTMLLines: StringLines {
get throws {
var result = try prolog.prettyHTMLLines
result.append(contentsOf: try rootElement.prettyHTMLLines)
result.append(contentsOf: try miscellanies.prettyHTMLLines)
return result
}
}

public func prettyXHTMLString(indent: String.Indent = .default,
newline: Character.Newline = .lineFeed) -> String {
return self.prettyXHTMLLines._description(indent: indent, newline: newline)
}

public func prettyHTMLString(
indent: String.Indent = .default,
newline: Character.Newline = .lineFeed
) throws -> String {
return try prettyHTMLLines._description(indent: indent, newline: newline)
}

public var prettyXHTMLString: String {
return self.prettyXHTMLString()
}

public var prettyHTMLString: String {
get throws {
return try prettyHTMLString()
}
}

public var prettyXHTMLData: Data? {
return self.prettyXHTMLLines.data(using: self.prolog.stringEncoding)
}

public var prettyHTMLData: Data? {
get throws {
return try prettyHTMLLines.data(using: self.prolog.stringEncoding)
}
}
}

extension Document {
Expand Down
81 changes: 79 additions & 2 deletions Sources/XHTML/Element.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* *************************************************************************************************
Element.swift
© 2019,2021 YOCKOW.
© 2019,2021,2023 YOCKOW.
Licensed under MIT License.
See "LICENSE.txt" for more information.
************************************************************************************************ */
Expand Down Expand Up @@ -75,7 +75,7 @@ open class Element: Node {
internal var _descendantTextNodesShouldUseMinimumAmpersandEncoding: Bool {
return false
}

open override var xhtmlString: String {
let tagName = self.name.description

Expand All @@ -96,6 +96,37 @@ open class Element: Node {
return result

}

private var _htmlTagName: String {
if namespace(for: name) == ._xhtmlNamespace {
return name.localName.description
}
return name.description
}

open override var htmlString: String {
get throws {
let tagName = _htmlTagName
var result = "<\(tagName)"

if !attributes.isEmpty {
let attrHTML = attributes.htmlString
if !attrHTML.isEmpty {
result += " \(attributes.htmlString)"
}
}

if self.isEmpty {
return result + " />" // Ref. https://developer.mozilla.org/en-US/docs/Glossary/Void_element
}

result += ">"
result += try children.map({ try $0.htmlString }).joined()
result += "</\(tagName)>"

return result
}
}

open override var prettyXHTMLLines: StringLines {
let tagName = self.name.description
Expand Down Expand Up @@ -140,6 +171,52 @@ open class Element: Node {

return result
}

open override var prettyHTMLLines: StringLines {
get throws {
let tagName = _htmlTagName

var result = StringLines()

do { // Start Tag
var attributesLines = self.attributes.prettyHTMLLines
switch attributesLines.count {
case 0:
result.append("<\(tagName)")
case 1:
result.append("<\(tagName) \(attributesLines[0].payload)")
default:
attributesLines.shiftRight()
result.append("<\(tagName)")
result.append(contentsOf: attributesLines)
}
result[result.endIndex - 1].payload += self.isEmpty ? " />" : ">"
}

let endTag = "</\(tagName)>"
appendChildrenAndEndTag: do {
if self.isEmpty { break appendChildrenAndEndTag }

var childrenLines = try children.reduce(into: StringLines()) {
$0.append(contentsOf: try $1.prettyHTMLLines)
}
if result.count == 1 && childrenLines.count <= 1 {
let startTagWidth = result[0].payloadProperties.estimatedWidth
let childWidth = childrenLines.first?.payloadProperties.estimatedWidth ?? 0
let endTagWidth = endTag.estimatedWidth
if startTagWidth + childWidth + endTagWidth < 100 {
result[0].payload += (childrenLines.first?.payload ?? "") + endTag
break appendChildrenAndEndTag
}
}
childrenLines.shiftRight()
result.append(contentsOf: childrenLines)
result.append(String.Line(endTag)!)
}

return result
}
}

internal func _append(_ child: Node) throws {
try child._setParent(self)
Expand Down

0 comments on commit f0326c7

Please sign in to comment.