Skip to content

Commit

Permalink
Create custom sequence to access child nodes (#228)
Browse files Browse the repository at this point in the history
* Create sequence type for child nodes.

* Directly convert DownRenderable to Document

* Remove childSequence requirement from Node protocol. Add to the extension instead.

* Remove toDocument requirement from the DownASTRenderable protocol.

* Make documentation for DownASTRenderable.toDocument more clear

Co-authored-by: Rob Phillips <rob@getkeepsafe.com>
  • Loading branch information
5sw and iwasrobbed-ks committed Oct 9, 2020
1 parent 968ef0d commit 6689a8f
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 30 deletions.
4 changes: 4 additions & 0 deletions Down.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
14C5E33521877CE900D5380C /* DownView.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D41689B51CFFE6BB00E5802B /* DownView.bundle */; };
26CABB93252B4D490032183C /* ChildSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26CABB92252B4D490032183C /* ChildSequence.swift */; };
8A569F481E6B3ED2008BE2AC /* DownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43AE5D91CFFD0D0006E1522 /* DownView.swift */; };
8A569F491E6B3ED9008BE2AC /* blocks.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EF71CFA5D63008EEC6E /* blocks.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F4A1E6B3ED9008BE2AC /* buffer.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EF81CFA5D63008EEC6E /* buffer.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
Expand Down Expand Up @@ -211,6 +212,7 @@

/* Begin PBXFileReference section */
14C5E33621877FCD00D5380C /* DownView (macOS).bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = "DownView (macOS).bundle"; sourceTree = "<group>"; };
26CABB92252B4D490032183C /* ChildSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChildSequence.swift; sourceTree = "<group>"; };
8A569F401E6B3E50008BE2AC /* Down.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Down.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8AFAEAFB1E6E32E900E09B68 /* DownTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DownTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8C73B9B522A687C400C8E60F /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
Expand Down Expand Up @@ -708,6 +710,7 @@
EEEBEE68225D2B1200AE438D /* Strong.swift */,
EEEBEE5A225D2A7E00AE438D /* Text.swift */,
EEEBEE58225D2A7000AE438D /* ThematicBreak.swift */,
26CABB92252B4D490032183C /* ChildSequence.swift */,
);
path = Nodes;
sourceTree = "<group>";
Expand Down Expand Up @@ -942,6 +945,7 @@
EEEBEE63225D2AD400AE438D /* HtmlInline.swift in Sources */,
8A569F621E6B3ED9008BE2AC /* node.c in Sources */,
EE4484932301F2DB0065C836 /* CGRect+Helpers.swift in Sources */,
26CABB93252B4D490032183C /* ChildSequence.swift in Sources */,
EEEBEE6D225D2B3200AE438D /* Image.swift in Sources */,
EED8DA9722BECD7500E54492 /* FontCollection.swift in Sources */,
EEEBEE4D225D2A0200AE438D /* Item.swift in Sources */,
Expand Down
20 changes: 2 additions & 18 deletions Source/AST/Nodes/BaseNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,8 @@ import libcmark
public class BaseNode: Node {

public let cmarkNode: CMarkNode

public private(set) lazy var children: [Node] = {
var result: [Node] = []
var child = cmark_node_first_child(cmarkNode)

while let raw = child {

guard let node = raw.wrap() else {
assertionFailure("Couldn't wrap node of type: \(raw.type)")
continue
}

result.append(node)
child = cmark_node_next(child)
}

return result
}()

public private(set) lazy var children: [Node] = Array(childSequence)

public private(set) lazy var nestDepth: Int = {
var depth = 0
Expand Down
34 changes: 34 additions & 0 deletions Source/AST/Nodes/ChildSequence.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// ChildSequence.swift
// Down
//
// Created by Sven Weidauer on 05.10.2020
//

import libcmark

/// Sequence of child nodes
public struct ChildSequence: Sequence {
let node: CMarkNode

public struct Iterator: IteratorProtocol {
var node: CMarkNode?

public mutating func next() -> Node? {
guard let node = node else { return nil }
defer { self.node = cmark_node_next(node) }

guard let result = node.wrap() else {
assertionFailure("Couldn't wrap node of type: \(node.type)")
return nil
}

return result
}
}

public func makeIterator() -> Iterator {
return Iterator(node: cmark_node_first_child(node))
}
}

5 changes: 5 additions & 0 deletions Source/AST/Nodes/Node.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public extension Node {
var hasSuccessor: Bool {
return cmark_node_next(cmarkNode) != nil
}

/// Sequence of wrapped child nodes.
var childSequence: ChildSequence {
return ChildSequence(node: cmarkNode)
}
}

// MARK: - Helper extensions
Expand Down
2 changes: 1 addition & 1 deletion Source/AST/Visitors/Visitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public protocol Visitor {

extension Visitor {
public func visitChildren(of node: Node) -> [Result] {
return node.children.compactMap { child in
return node.childSequence.compactMap { child in
switch child {
case let child as Document: return visit(document: child)
case let child as BlockQuote: return visit(blockQuote: child)
Expand Down
15 changes: 15 additions & 0 deletions Source/Renderers/DownASTRenderable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ extension DownASTRenderable {
public func toAST(_ options: DownOptions = .default) throws -> UnsafeMutablePointer<cmark_node> {
return try DownASTRenderer.stringToAST(markdownString, options: options)
}

/// Parses the `markdownString` property into an abstract syntax tree and returns the root `Document` node.
///
/// - Parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.default`
/// - Returns: The root Document node for the abstract syntax tree representation of the Markdown input
/// - Throws: `MarkdownToASTError` if conversion fails
public func toDocument(_ options: DownOptions = .default) throws -> Document {
let tree = try toAST(options)

guard tree.type == CMARK_NODE_DOCUMENT else {
throw DownErrors.astRenderingError
}

return Document(cmarkNode: tree)
}
}

public struct DownASTRenderer {
Expand Down
8 changes: 1 addition & 7 deletions Source/Renderers/DownAttributedStringRenderable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,7 @@ extension DownAttributedStringRenderable {
/// - Returns: An `NSAttributedString`
/// - Throws: `DownErrors` depending on the scenario
public func toAttributedString(_ options: DownOptions = .default, styler: Styler) throws -> NSAttributedString {
let tree = try self.toAST(options)

guard tree.type == CMARK_NODE_DOCUMENT else {
throw DownErrors.astRenderingError
}

let document = Document(cmarkNode: tree)
let document = try self.toDocument(options)
let visitor = AttributedStringVisitor(styler: styler, options: options)
return document.accept(visitor)
}
Expand Down
3 changes: 1 addition & 2 deletions Tests/AST/NodeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ extension NodeTests {

private func parse(_ markdown: String, andVisitWith visitor: NodeVisitor) {
do {
let ast = try Down(markdownString: markdown).toAST()
let document = Document(cmarkNode: ast)
let document = try Down(markdownString: markdown).toDocument()
document.accept(visitor)
} catch {
XCTFail()
Expand Down
3 changes: 1 addition & 2 deletions Tests/AST/VisitorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ class VisitorTests: XCTestCase {

func debugResult(for markdown: String) -> String {
let down = Down(markdownString: markdown)
let ast = try! down.toAST()
let document = Document(cmarkNode: ast)
let document = try! down.toDocument()
return document.accept(DebugVisitor())
}

Expand Down

0 comments on commit 6689a8f

Please sign in to comment.