119 lines
2.2 KiB
V
119 lines
2.2 KiB
V
// Copyright 2026 The V Language. All rights reserved.
|
|
// Use of this source code is governed by an MIT license
|
|
// that can be found in the LICENSE file.
|
|
module markdown
|
|
|
|
import strings
|
|
|
|
// NodeKind identifies what kind of AST node a Node represents.
|
|
pub enum NodeKind {
|
|
document
|
|
heading
|
|
paragraph
|
|
blockquote
|
|
list
|
|
list_item
|
|
code_block
|
|
fenced_code
|
|
thematic_break
|
|
html_block
|
|
link_ref_def
|
|
table
|
|
table_head
|
|
table_body
|
|
table_row
|
|
table_cell
|
|
definition_list
|
|
definition_term
|
|
definition_desc
|
|
footnote_def
|
|
text
|
|
emphasis
|
|
strong
|
|
code_span
|
|
link
|
|
image
|
|
autolink
|
|
raw_html
|
|
hard_break
|
|
soft_break
|
|
strikethrough
|
|
footnote_ref
|
|
task_checkbox
|
|
}
|
|
|
|
// Alignment is the text alignment of a table cell column.
|
|
pub enum Alignment {
|
|
none_
|
|
left
|
|
center
|
|
right
|
|
}
|
|
|
|
// Node is a node in the parsed markdown AST.
|
|
// A document is a tree of Nodes with .document as the root.
|
|
@[heap]
|
|
pub struct Node {
|
|
pub mut:
|
|
kind NodeKind
|
|
level int
|
|
is_tight bool
|
|
is_ordered bool
|
|
list_start int = 1
|
|
fence_info string
|
|
literal string
|
|
dest string
|
|
title string
|
|
label string
|
|
checked bool
|
|
align Alignment
|
|
id string
|
|
fn_label string
|
|
fn_index int
|
|
children []&Node
|
|
}
|
|
|
|
// new_node allocates and returns a new Node of the given kind.
|
|
pub fn new_node(kind NodeKind) &Node {
|
|
return &Node{
|
|
kind: kind
|
|
}
|
|
}
|
|
|
|
// append_child appends child as the last child of n.
|
|
pub fn (mut n Node) append_child(child &Node) {
|
|
n.children << child
|
|
}
|
|
|
|
// text_content returns the plain-text content of this node and all descendants,
|
|
// concatenated in document order.
|
|
pub fn (n &Node) text_content() string {
|
|
match n.kind {
|
|
.text, .code_span, .raw_html {
|
|
return n.literal
|
|
}
|
|
else {
|
|
mut sb := strings.new_builder(64)
|
|
for child in n.children {
|
|
sb.write_string(child.text_content())
|
|
}
|
|
return sb.str()
|
|
}
|
|
}
|
|
}
|
|
|
|
// walk traverses n and all its descendants in pre-order (root before children).
|
|
// The callback f receives each node; return false from f to stop traversal early.
|
|
// walk itself returns false if traversal was stopped, true otherwise.
|
|
pub fn (n &Node) walk(f fn (&Node) bool) bool {
|
|
if !f(n) {
|
|
return false
|
|
}
|
|
for child in n.children {
|
|
if !child.walk(f) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|