vendor/github.com/russross/blackfriday/v2/node.go
changeset 256 6d9efbef00a9
child 260 445e01aede7e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/github.com/russross/blackfriday/v2/node.go	Sun Jul 11 10:35:56 2021 +0200
@@ -0,0 +1,354 @@
+package blackfriday
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// NodeType specifies a type of a single node of a syntax tree. Usually one
+// node (and its type) corresponds to a single markdown feature, e.g. emphasis
+// or code block.
+type NodeType int
+
+// Constants for identifying different types of nodes. See NodeType.
+const (
+	Document NodeType = iota
+	BlockQuote
+	List
+	Item
+	Paragraph
+	Heading
+	HorizontalRule
+	Emph
+	Strong
+	Del
+	Link
+	Image
+	Text
+	HTMLBlock
+	CodeBlock
+	Softbreak
+	Hardbreak
+	Code
+	HTMLSpan
+	Table
+	TableCell
+	TableHead
+	TableBody
+	TableRow
+)
+
+var nodeTypeNames = []string{
+	Document:       "Document",
+	BlockQuote:     "BlockQuote",
+	List:           "List",
+	Item:           "Item",
+	Paragraph:      "Paragraph",
+	Heading:        "Heading",
+	HorizontalRule: "HorizontalRule",
+	Emph:           "Emph",
+	Strong:         "Strong",
+	Del:            "Del",
+	Link:           "Link",
+	Image:          "Image",
+	Text:           "Text",
+	HTMLBlock:      "HTMLBlock",
+	CodeBlock:      "CodeBlock",
+	Softbreak:      "Softbreak",
+	Hardbreak:      "Hardbreak",
+	Code:           "Code",
+	HTMLSpan:       "HTMLSpan",
+	Table:          "Table",
+	TableCell:      "TableCell",
+	TableHead:      "TableHead",
+	TableBody:      "TableBody",
+	TableRow:       "TableRow",
+}
+
+func (t NodeType) String() string {
+	return nodeTypeNames[t]
+}
+
+// ListData contains fields relevant to a List and Item node type.
+type ListData struct {
+	ListFlags       ListType
+	Tight           bool   // Skip <p>s around list item data if true
+	BulletChar      byte   // '*', '+' or '-' in bullet lists
+	Delimiter       byte   // '.' or ')' after the number in ordered lists
+	RefLink         []byte // If not nil, turns this list item into a footnote item and triggers different rendering
+	IsFootnotesList bool   // This is a list of footnotes
+}
+
+// LinkData contains fields relevant to a Link node type.
+type LinkData struct {
+	Destination []byte // Destination is what goes into a href
+	Title       []byte // Title is the tooltip thing that goes in a title attribute
+	NoteID      int    // NoteID contains a serial number of a footnote, zero if it's not a footnote
+	Footnote    *Node  // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil.
+}
+
+// CodeBlockData contains fields relevant to a CodeBlock node type.
+type CodeBlockData struct {
+	IsFenced    bool   // Specifies whether it's a fenced code block or an indented one
+	Info        []byte // This holds the info string
+	FenceChar   byte
+	FenceLength int
+	FenceOffset int
+}
+
+// TableCellData contains fields relevant to a TableCell node type.
+type TableCellData struct {
+	IsHeader bool           // This tells if it's under the header row
+	Align    CellAlignFlags // This holds the value for align attribute
+}
+
+// HeadingData contains fields relevant to a Heading node type.
+type HeadingData struct {
+	Level        int    // This holds the heading level number
+	HeadingID    string // This might hold heading ID, if present
+	IsTitleblock bool   // Specifies whether it's a title block
+}
+
+// Node is a single element in the abstract syntax tree of the parsed document.
+// It holds connections to the structurally neighboring nodes and, for certain
+// types of nodes, additional information that might be needed when rendering.
+type Node struct {
+	Type       NodeType // Determines the type of the node
+	Parent     *Node    // Points to the parent
+	FirstChild *Node    // Points to the first child, if any
+	LastChild  *Node    // Points to the last child, if any
+	Prev       *Node    // Previous sibling; nil if it's the first child
+	Next       *Node    // Next sibling; nil if it's the last child
+
+	Literal []byte // Text contents of the leaf nodes
+
+	HeadingData   // Populated if Type is Heading
+	ListData      // Populated if Type is List
+	CodeBlockData // Populated if Type is CodeBlock
+	LinkData      // Populated if Type is Link
+	TableCellData // Populated if Type is TableCell
+
+	content []byte // Markdown content of the block nodes
+	open    bool   // Specifies an open block node that has not been finished to process yet
+}
+
+// NewNode allocates a node of a specified type.
+func NewNode(typ NodeType) *Node {
+	return &Node{
+		Type: typ,
+		open: true,
+	}
+}
+
+func (n *Node) String() string {
+	ellipsis := ""
+	snippet := n.Literal
+	if len(snippet) > 16 {
+		snippet = snippet[:16]
+		ellipsis = "..."
+	}
+	return fmt.Sprintf("%s: '%s%s'", n.Type, snippet, ellipsis)
+}
+
+// Unlink removes node 'n' from the tree.
+// It panics if the node is nil.
+func (n *Node) Unlink() {
+	if n.Prev != nil {
+		n.Prev.Next = n.Next
+	} else if n.Parent != nil {
+		n.Parent.FirstChild = n.Next
+	}
+	if n.Next != nil {
+		n.Next.Prev = n.Prev
+	} else if n.Parent != nil {
+		n.Parent.LastChild = n.Prev
+	}
+	n.Parent = nil
+	n.Next = nil
+	n.Prev = nil
+}
+
+// AppendChild adds a node 'child' as a child of 'n'.
+// It panics if either node is nil.
+func (n *Node) AppendChild(child *Node) {
+	child.Unlink()
+	child.Parent = n
+	if n.LastChild != nil {
+		n.LastChild.Next = child
+		child.Prev = n.LastChild
+		n.LastChild = child
+	} else {
+		n.FirstChild = child
+		n.LastChild = child
+	}
+}
+
+// InsertBefore inserts 'sibling' immediately before 'n'.
+// It panics if either node is nil.
+func (n *Node) InsertBefore(sibling *Node) {
+	sibling.Unlink()
+	sibling.Prev = n.Prev
+	if sibling.Prev != nil {
+		sibling.Prev.Next = sibling
+	}
+	sibling.Next = n
+	n.Prev = sibling
+	sibling.Parent = n.Parent
+	if sibling.Prev == nil {
+		sibling.Parent.FirstChild = sibling
+	}
+}
+
+func (n *Node) isContainer() bool {
+	switch n.Type {
+	case Document:
+		fallthrough
+	case BlockQuote:
+		fallthrough
+	case List:
+		fallthrough
+	case Item:
+		fallthrough
+	case Paragraph:
+		fallthrough
+	case Heading:
+		fallthrough
+	case Emph:
+		fallthrough
+	case Strong:
+		fallthrough
+	case Del:
+		fallthrough
+	case Link:
+		fallthrough
+	case Image:
+		fallthrough
+	case Table:
+		fallthrough
+	case TableHead:
+		fallthrough
+	case TableBody:
+		fallthrough
+	case TableRow:
+		fallthrough
+	case TableCell:
+		return true
+	default:
+		return false
+	}
+}
+
+func (n *Node) canContain(t NodeType) bool {
+	if n.Type == List {
+		return t == Item
+	}
+	if n.Type == Document || n.Type == BlockQuote || n.Type == Item {
+		return t != Item
+	}
+	if n.Type == Table {
+		return t == TableHead || t == TableBody
+	}
+	if n.Type == TableHead || n.Type == TableBody {
+		return t == TableRow
+	}
+	if n.Type == TableRow {
+		return t == TableCell
+	}
+	return false
+}
+
+// WalkStatus allows NodeVisitor to have some control over the tree traversal.
+// It is returned from NodeVisitor and different values allow Node.Walk to
+// decide which node to go to next.
+type WalkStatus int
+
+const (
+	// GoToNext is the default traversal of every node.
+	GoToNext WalkStatus = iota
+	// SkipChildren tells walker to skip all children of current node.
+	SkipChildren
+	// Terminate tells walker to terminate the traversal.
+	Terminate
+)
+
+// NodeVisitor is a callback to be called when traversing the syntax tree.
+// Called twice for every node: once with entering=true when the branch is
+// first visited, then with entering=false after all the children are done.
+type NodeVisitor func(node *Node, entering bool) WalkStatus
+
+// Walk is a convenience method that instantiates a walker and starts a
+// traversal of subtree rooted at n.
+func (n *Node) Walk(visitor NodeVisitor) {
+	w := newNodeWalker(n)
+	for w.current != nil {
+		status := visitor(w.current, w.entering)
+		switch status {
+		case GoToNext:
+			w.next()
+		case SkipChildren:
+			w.entering = false
+			w.next()
+		case Terminate:
+			return
+		}
+	}
+}
+
+type nodeWalker struct {
+	current  *Node
+	root     *Node
+	entering bool
+}
+
+func newNodeWalker(root *Node) *nodeWalker {
+	return &nodeWalker{
+		current:  root,
+		root:     root,
+		entering: true,
+	}
+}
+
+func (nw *nodeWalker) next() {
+	if (!nw.current.isContainer() || !nw.entering) && nw.current == nw.root {
+		nw.current = nil
+		return
+	}
+	if nw.entering && nw.current.isContainer() {
+		if nw.current.FirstChild != nil {
+			nw.current = nw.current.FirstChild
+			nw.entering = true
+		} else {
+			nw.entering = false
+		}
+	} else if nw.current.Next == nil {
+		nw.current = nw.current.Parent
+		nw.entering = false
+	} else {
+		nw.current = nw.current.Next
+		nw.entering = true
+	}
+}
+
+func dump(ast *Node) {
+	fmt.Println(dumpString(ast))
+}
+
+func dumpR(ast *Node, depth int) string {
+	if ast == nil {
+		return ""
+	}
+	indent := bytes.Repeat([]byte("\t"), depth)
+	content := ast.Literal
+	if content == nil {
+		content = ast.content
+	}
+	result := fmt.Sprintf("%s%s(%q)\n", indent, ast.Type, content)
+	for n := ast.FirstChild; n != nil; n = n.Next {
+		result += dumpR(n, depth+1)
+	}
+	return result
+}
+
+func dumpString(ast *Node) string {
+	return dumpR(ast, 0)
+}