Skip to content

Commit

Permalink
[Feature] Create API for parsing to AST and NSAttributedString (#132)
Browse files Browse the repository at this point in the history
* Create Node wrapper

* Categorize nodes into classes

* Add debug descriptions

* Define Visitor

* Add simple test for demonstration purposes

* Move nodes into separate files

* Move visitors into separate files

* Tidy up

* Expose Visitor protocol

* Add accept method to Document

* Update various nodes

* WIP: AttributedStringVisitor

* Fill out remaining visit methods

* Move Styler protocol into its own file

* Append blank line only for nodes with successors

* Add prefixes to list items

* Style list prefixes

* Rename isLast

* Adjust accept signature

* Adjust Image and Link nodes

* Pass url to styler methods

* Provide API to render to an attributed string via the AST

* Fix Link & Image properties

* Pass fenceInfo to styler method

* Slight refactoring of nodes

* Improve DebugVisitor to print tree depth

* Tidy up

* More tidy up

* Add some descriptions

* Tidy up

* Add documentation

* Make nodes public

* Tidy up

* More documentation

* Add visitor test

* Fix compile error for Xcode 10.1

* Remove unnecessary line breaks from blocks

* Test AttributedStringVisitor

* Make lazy var private(set)

* Clean up TODO

* Make all cmarkNode reference immutable

* Don’t fatalError on list type

* Don’t fatalError when wrapping child nodes

* Tidy up

* Don’t fatalError when visiting children

* Tidy up doc comments

* Improve documentation

* Refactor Node initialization

* Expose wrap() method

* Tidy up

* Fix warnings

* Lazily compute children

* Fix typo
  • Loading branch information
johnxnguyen authored and rob phillips committed Apr 21, 2019
1 parent 6e566e2 commit c70d824
Show file tree
Hide file tree
Showing 36 changed files with 1,448 additions and 23 deletions.
140 changes: 140 additions & 0 deletions Down.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions Source/AST/Nodes/BaseNode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// BaseNode.swift
// Down
//
// Created by John Nguyen on 21.04.19.
//
//

import Foundation
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
}()

init(cmarkNode: CMarkNode) {
self.cmarkNode = cmarkNode
}
}
21 changes: 21 additions & 0 deletions Source/AST/Nodes/BlockQuote.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// BlockQuote.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class BlockQuote: BaseNode {}


// MARK: - Debug

extension BlockQuote: CustomDebugStringConvertible {

public var debugDescription: String {
return "Block Quote"
}
}
25 changes: 25 additions & 0 deletions Source/AST/Nodes/Code.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Code.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class Code: BaseNode {

/// The code content, if present.
public private(set) lazy var literal: String? = cmarkNode.literal
}


// MARK: - Debug

extension Code: CustomDebugStringConvertible {

public var debugDescription: String {
return "Code - \(literal ?? "nil")"
}
}
38 changes: 38 additions & 0 deletions Source/AST/Nodes/CodeBlock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// CodeBlock.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class CodeBlock: BaseNode {

/// The code content, if present.
public private(set) lazy var literal: String? = cmarkNode.literal

/// The fence info is an optional string that trails the opening sequence of backticks.
/// It can be used to provide some contextual information about the block, such as
/// the name of a programming language.
///
/// For example:
/// ```
/// '''<fence info>
/// <literal>
/// '''
/// ```
///
public private(set) lazy var fenceInfo: String? = cmarkNode.fenceInfo
}


// MARK: - Debug

extension CodeBlock: CustomDebugStringConvertible {

public var debugDescription: String {
return "Code Block - \(literal ?? "nil"), fenceInfo: \(fenceInfo ?? "nil")"
}
}
25 changes: 25 additions & 0 deletions Source/AST/Nodes/CustomBlock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// CustomBlock.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class CustomBlock: BaseNode {

/// The custom content, if present.
public private(set) lazy var literal: String? = cmarkNode.literal
}


// MARK: - Debug

extension CustomBlock: CustomDebugStringConvertible {

public var debugDescription: String {
return "Custom Block - \(literal ?? "nil")"
}
}
25 changes: 25 additions & 0 deletions Source/AST/Nodes/CustomInline.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// CustomInline.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class CustomInline: BaseNode {

/// The custom content, if present.
public private(set) lazy var literal: String? = cmarkNode.literal
}


// MARK: - Debug

extension CustomInline: CustomDebugStringConvertible {

public var debugDescription: String {
return "Custom Inline - \(literal ?? "nil")"
}
}
32 changes: 32 additions & 0 deletions Source/AST/Nodes/Document.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Document.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class Document: BaseNode {

deinit {
// Frees the node and all its children.
cmark_node_free(cmarkNode)
}

/// Accepts the given visitor and return its result.
public func accept<T: Visitor>(_ visitor: T) -> T.Result {
return visitor.visit(document: self)
}
}


// MARK: - Debug

extension Document: CustomDebugStringConvertible {

public var debugDescription: String {
return "Document"
}
}
21 changes: 21 additions & 0 deletions Source/AST/Nodes/Emphasis.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Emphasis.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class Emphasis: BaseNode {}


// MARK: - Debug

extension Emphasis: CustomDebugStringConvertible {

public var debugDescription: String {
return "Emphasis"
}
}
25 changes: 25 additions & 0 deletions Source/AST/Nodes/Heading.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Heading.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class Heading: BaseNode {

/// The level of the heading, a value between 1 and 6.
public private(set) lazy var headingLevel: Int = cmarkNode.headingLevel
}


// MARK: - Debug

extension Heading: CustomDebugStringConvertible {

public var debugDescription: String {
return "Heading - L\(headingLevel)"
}
}
25 changes: 25 additions & 0 deletions Source/AST/Nodes/HtmlBlock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// HtmlBlock.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class HtmlBlock: BaseNode {

/// The html content, if present.
public private(set) lazy var literal: String? = cmarkNode.literal
}


// MARK: - Debug

extension HtmlBlock: CustomDebugStringConvertible {

public var debugDescription: String {
return "Html Block - \(literal ?? "nil")"
}
}
25 changes: 25 additions & 0 deletions Source/AST/Nodes/HtmlInline.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// HtmlInline.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class HtmlInline: BaseNode {

/// The html tag, if present.
public private(set) lazy var literal: String? = cmarkNode.literal
}


// MARK: - Debug

extension HtmlInline: CustomDebugStringConvertible {

public var debugDescription: String {
return "Html Inline - \(literal ?? "nil")"
}
}
46 changes: 46 additions & 0 deletions Source/AST/Nodes/Image.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// Image.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class Image: BaseNode {

/// The title of the image, if present.
///
/// In the example below, the first line is a reference link, with the reference at the
/// bottom. `<text>` is literal text belonging to children nodes. The title occurs
/// after the url and is optional.
///
/// ```
/// ![<text>][<id>]
/// ...
/// [<id>]: <url> "<title>"
/// ```
///
public private(set) lazy var title: String? = cmarkNode.title

/// The url of the image, if present.
///
/// For example:
///
/// ```
/// ![<text>](<url>)
/// ```
///
public private(set) lazy var url: String? = cmarkNode.url
}


// MARK: - Debug

extension Image: CustomDebugStringConvertible {

public var debugDescription: String {
return "Image - title: \(title ?? "nil"), url: \(url ?? "nil"))"
}
}
21 changes: 21 additions & 0 deletions Source/AST/Nodes/Item.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Item.swift
// Down
//
// Created by John Nguyen on 09.04.19.
//

import Foundation
import libcmark

public class Item: BaseNode {}


// MARK: - Debug

extension Item: CustomDebugStringConvertible {

public var debugDescription: String {
return "Item"
}
}
Loading

0 comments on commit c70d824

Please sign in to comment.