Fix all headings wrongly referred to as headers

I've left test cases alone since can't lean on the compiler for
crosschecking there.

Fixes #330.
This commit is contained in:
Vytautas Šaltenis 2017-02-12 19:00:18 +02:00
parent ad7f7c56d5
commit 747587a52d
6 changed files with 89 additions and 89 deletions

View File

@ -224,7 +224,7 @@ are a few of note:
* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown): * [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown):
provides a GitHub Flavored Markdown renderer with fenced code block provides a GitHub Flavored Markdown renderer with fenced code block
highlighting, clickable header anchor links. highlighting, clickable heading anchor links.
It's not customizable, and its goal is to produce HTML output It's not customizable, and its goal is to produce HTML output
equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode), equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode),

View File

@ -43,14 +43,14 @@ func (p *parser) block(data []byte) {
// parse out one block-level construct at a time // parse out one block-level construct at a time
for len(data) > 0 { for len(data) > 0 {
// prefixed header: // prefixed heading:
// //
// # Header 1 // # Heading 1
// ## Header 2 // ## Heading 2
// ... // ...
// ###### Header 6 // ###### Heading 6
if p.isPrefixHeader(data) { if p.isPrefixHeading(data) {
data = data[p.prefixHeader(data):] data = data[p.prefixHeading(data):]
continue continue
} }
@ -190,7 +190,7 @@ func (p *parser) block(data []byte) {
} }
// anything else must look like a normal paragraph // anything else must look like a normal paragraph
// note: this finds underlined headers, too // note: this finds underlined headings, too
data = data[p.paragraph(data):] data = data[p.paragraph(data):]
} }
@ -204,12 +204,12 @@ func (p *parser) addBlock(typ NodeType, content []byte) *Node {
return container return container
} }
func (p *parser) isPrefixHeader(data []byte) bool { func (p *parser) isPrefixHeading(data []byte) bool {
if data[0] != '#' { if data[0] != '#' {
return false return false
} }
if p.flags&SpaceHeaders != 0 { if p.flags&SpaceHeadings != 0 {
level := 0 level := 0
for level < 6 && level < len(data) && data[level] == '#' { for level < 6 && level < len(data) && data[level] == '#' {
level++ level++
@ -221,7 +221,7 @@ func (p *parser) isPrefixHeader(data []byte) bool {
return true return true
} }
func (p *parser) prefixHeader(data []byte) int { func (p *parser) prefixHeading(data []byte) int {
level := 0 level := 0
for level < 6 && level < len(data) && data[level] == '#' { for level < 6 && level < len(data) && data[level] == '#' {
level++ level++
@ -230,14 +230,14 @@ func (p *parser) prefixHeader(data []byte) int {
end := skipUntilChar(data, i, '\n') end := skipUntilChar(data, i, '\n')
skip := end skip := end
id := "" id := ""
if p.flags&HeaderIDs != 0 { if p.flags&HeadingIDs != 0 {
j, k := 0, 0 j, k := 0, 0
// find start/end of header id // find start/end of heading id
for j = i; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ { for j = i; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ {
} }
for k = j + 1; k < end && data[k] != '}'; k++ { for k = j + 1; k < end && data[k] != '}'; k++ {
} }
// extract header id iff found // extract heading id iff found
if j < end && k < end { if j < end && k < end {
id = string(data[j+2 : k]) id = string(data[j+2 : k])
end = j end = j
@ -257,18 +257,18 @@ func (p *parser) prefixHeader(data []byte) int {
end-- end--
} }
if end > i { if end > i {
if id == "" && p.flags&AutoHeaderIDs != 0 { if id == "" && p.flags&AutoHeadingIDs != 0 {
id = sanitized_anchor_name.Create(string(data[i:end])) id = sanitized_anchor_name.Create(string(data[i:end]))
} }
block := p.addBlock(Header, data[i:end]) block := p.addBlock(Heading, data[i:end])
block.HeaderID = id block.HeadingID = id
block.Level = level block.Level = level
} }
return skip return skip
} }
func (p *parser) isUnderlinedHeader(data []byte) int { func (p *parser) isUnderlinedHeading(data []byte) int {
// test of level 1 header // test of level 1 heading
if data[0] == '=' { if data[0] == '=' {
i := skipChar(data, 1, '=') i := skipChar(data, 1, '=')
i = skipChar(data, i, ' ') i = skipChar(data, i, ' ')
@ -278,7 +278,7 @@ func (p *parser) isUnderlinedHeader(data []byte) int {
return 0 return 0
} }
// test of level 2 header // test of level 2 heading
if data[0] == '-' { if data[0] == '-' {
i := skipChar(data, 1, '-') i := skipChar(data, 1, '-')
i = skipChar(data, i, ' ') i = skipChar(data, i, ' ')
@ -308,7 +308,7 @@ func (p *parser) titleBlock(data []byte, doRender bool) int {
consumed := len(data) consumed := len(data)
data = bytes.TrimPrefix(data, []byte("% ")) data = bytes.TrimPrefix(data, []byte("% "))
data = bytes.Replace(data, []byte("\n% "), []byte("\n"), -1) data = bytes.Replace(data, []byte("\n% "), []byte("\n"), -1)
block := p.addBlock(Header, data) block := p.addBlock(Heading, data)
block.Level = 1 block.Level = 1
block.IsTitleblock = true block.IsTitleblock = true
@ -1301,9 +1301,9 @@ gatherlines:
sublist = raw.Len() sublist = raw.Len()
} }
// is this a nested prefix header? // is this a nested prefix heading?
case p.isPrefixHeader(chunk): case p.isPrefixHeading(chunk):
// if the header is not indented, it is not nested in the list // if the heading is not indented, it is not nested in the list
// and thus ends the list // and thus ends the list
if containsBlankLine && indent < 4 { if containsBlankLine && indent < 4 {
*flags |= ListItemEndOfList *flags |= ListItemEndOfList
@ -1445,9 +1445,9 @@ func (p *parser) paragraph(data []byte) int {
return i + n return i + n
} }
// an underline under some text marks a header, so our paragraph ended on prev line // an underline under some text marks a heading, so our paragraph ended on prev line
if i > 0 { if i > 0 {
if level := p.isUnderlinedHeader(current); level > 0 { if level := p.isUnderlinedHeading(current); level > 0 {
// render the paragraph // render the paragraph
p.renderParagraph(data[:prev]) p.renderParagraph(data[:prev])
@ -1461,13 +1461,13 @@ func (p *parser) paragraph(data []byte) int {
} }
id := "" id := ""
if p.flags&AutoHeaderIDs != 0 { if p.flags&AutoHeadingIDs != 0 {
id = sanitized_anchor_name.Create(string(data[prev:eol])) id = sanitized_anchor_name.Create(string(data[prev:eol]))
} }
block := p.addBlock(Header, data[prev:eol]) block := p.addBlock(Heading, data[prev:eol])
block.Level = level block.Level = level
block.HeaderID = id block.HeadingID = id
// find the end of the underline // find the end of the underline
for i < len(data) && data[i] != '\n' { for i < len(data) && data[i] != '\n' {
@ -1486,8 +1486,8 @@ func (p *parser) paragraph(data []byte) int {
} }
} }
// if there's a prefixed header or a horizontal rule after this, paragraph is over // if there's a prefixed heading or a horizontal rule after this, paragraph is over
if p.isPrefixHeader(current) || p.isHRule(current) { if p.isPrefixHeading(current) || p.isHRule(current) {
p.renderParagraph(data[:i]) p.renderParagraph(data[:i])
return i return i
} }

View File

@ -144,7 +144,7 @@ func TestPrefixHeaderSpaceExtension(t *testing.T) {
"<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
"<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n", "<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n",
} }
doTestsBlock(t, tests, SpaceHeaders) doTestsBlock(t, tests, SpaceHeadings)
} }
func TestPrefixHeaderIdExtension(t *testing.T) { func TestPrefixHeaderIdExtension(t *testing.T) {
@ -204,7 +204,7 @@ func TestPrefixHeaderIdExtension(t *testing.T) {
"<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
"<h1 id=\"someid\">Nested header</h1></li>\n</ul></li>\n</ul>\n", "<h1 id=\"someid\">Nested header</h1></li>\n</ul></li>\n</ul>\n",
} }
doTestsBlock(t, tests, HeaderIDs) doTestsBlock(t, tests, HeadingIDs)
} }
func TestPrefixHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) { func TestPrefixHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) {
@ -248,12 +248,12 @@ func TestPrefixHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) {
} }
parameters := HTMLRendererParameters{ parameters := HTMLRendererParameters{
HeaderIDPrefix: "PRE:", HeadingIDPrefix: "PRE:",
HeaderIDSuffix: ":POST", HeadingIDSuffix: ":POST",
} }
doTestsParam(t, tests, TestParams{ doTestsParam(t, tests, TestParams{
Options: Options{Extensions: HeaderIDs}, Options: Options{Extensions: HeadingIDs},
HTMLFlags: UseXHTML, HTMLFlags: UseXHTML,
HTMLRendererParameters: parameters, HTMLRendererParameters: parameters,
}) })
@ -307,7 +307,7 @@ func TestPrefixAutoHeaderIdExtension(t *testing.T) {
"# Header\n\n# Header 1\n\n# Header\n\n# Header", "# Header\n\n# Header 1\n\n# Header\n\n# Header",
"<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header</h1>\n\n<h1 id=\"header-1-2\">Header</h1>\n", "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header</h1>\n\n<h1 id=\"header-1-2\">Header</h1>\n",
} }
doTestsBlock(t, tests, AutoHeaderIDs) doTestsBlock(t, tests, AutoHeadingIDs)
} }
func TestPrefixAutoHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) { func TestPrefixAutoHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) {
@ -360,12 +360,12 @@ func TestPrefixAutoHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) {
} }
parameters := HTMLRendererParameters{ parameters := HTMLRendererParameters{
HeaderIDPrefix: "PRE:", HeadingIDPrefix: "PRE:",
HeaderIDSuffix: ":POST", HeadingIDSuffix: ":POST",
} }
doTestsParam(t, tests, TestParams{ doTestsParam(t, tests, TestParams{
Options: Options{Extensions: AutoHeaderIDs}, Options: Options{Extensions: AutoHeadingIDs},
HTMLFlags: UseXHTML, HTMLFlags: UseXHTML,
HTMLRendererParameters: parameters, HTMLRendererParameters: parameters,
}) })
@ -376,7 +376,7 @@ func TestPrefixMultipleHeaderExtensions(t *testing.T) {
"# Header\n\n# Header {#header}\n\n# Header 1", "# Header\n\n# Header {#header}\n\n# Header 1",
"<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n", "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n",
} }
doTestsBlock(t, tests, AutoHeaderIDs|HeaderIDs) doTestsBlock(t, tests, AutoHeadingIDs|HeadingIDs)
} }
func TestUnderlineHeaders(t *testing.T) { func TestUnderlineHeaders(t *testing.T) {
@ -476,7 +476,7 @@ func TestUnderlineHeadersAutoIDs(t *testing.T) {
"Header 1\n========\n\nHeader 1\n========\n", "Header 1\n========\n\nHeader 1\n========\n",
"<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n", "<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n",
} }
doTestsBlock(t, tests, AutoHeaderIDs) doTestsBlock(t, tests, AutoHeadingIDs)
} }
func TestHorizontalRule(t *testing.T) { func TestHorizontalRule(t *testing.T) {

64
html.go
View File

@ -80,11 +80,11 @@ type HTMLRendererParameters struct {
// HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string // HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string
// <sup>[return]</sup> is used. // <sup>[return]</sup> is used.
FootnoteReturnLinkContents string FootnoteReturnLinkContents string
// If set, add this text to the front of each Header ID, to ensure // If set, add this text to the front of each Heading ID, to ensure
// uniqueness. // uniqueness.
HeaderIDPrefix string HeadingIDPrefix string
// If set, add this text to the back of each Header ID, to ensure uniqueness. // If set, add this text to the back of each Heading ID, to ensure uniqueness.
HeaderIDSuffix string HeadingIDSuffix string
Title string // Document title (used if CompletePage is set) Title string // Document title (used if CompletePage is set)
CSS string // Optional CSS file URL (used if CompletePage is set) CSS string // Optional CSS file URL (used if CompletePage is set)
@ -101,8 +101,8 @@ type HTMLRenderer struct {
closeTag string // how to end singleton tags: either " />" or ">" closeTag string // how to end singleton tags: either " />" or ">"
// Track header IDs to prevent ID collision in a single generation. // Track heading IDs to prevent ID collision in a single generation.
headerIDs map[string]int headingIDs map[string]int
lastOutputLen int lastOutputLen int
disableTags int disableTags int
@ -131,8 +131,8 @@ func NewHTMLRenderer(params HTMLRendererParameters) *HTMLRenderer {
return &HTMLRenderer{ return &HTMLRenderer{
HTMLRendererParameters: params, HTMLRendererParameters: params,
closeTag: closeTag, closeTag: closeTag,
headerIDs: make(map[string]int), headingIDs: make(map[string]int),
sr: NewSmartypantsRenderer(params.Flags), sr: NewSmartypantsRenderer(params.Flags),
} }
@ -238,20 +238,20 @@ func isRelativeLink(link []byte) (yes bool) {
return false return false
} }
func (r *HTMLRenderer) ensureUniqueHeaderID(id string) string { func (r *HTMLRenderer) ensureUniqueHeadingID(id string) string {
for count, found := r.headerIDs[id]; found; count, found = r.headerIDs[id] { for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] {
tmp := fmt.Sprintf("%s-%d", id, count+1) tmp := fmt.Sprintf("%s-%d", id, count+1)
if _, tmpFound := r.headerIDs[tmp]; !tmpFound { if _, tmpFound := r.headingIDs[tmp]; !tmpFound {
r.headerIDs[id] = count + 1 r.headingIDs[id] = count + 1
id = tmp id = tmp
} else { } else {
id = id + "-1" id = id + "-1"
} }
} }
if _, found := r.headerIDs[id]; !found { if _, found := r.headingIDs[id]; !found {
r.headerIDs[id] = 0 r.headingIDs[id] = 0
} }
return id return id
@ -457,7 +457,7 @@ var (
footnotesCloseDivBytes = []byte("\n</div>\n") footnotesCloseDivBytes = []byte("\n</div>\n")
) )
func headerTagsFromLevel(level int) ([]byte, []byte) { func headingTagsFromLevel(level int) ([]byte, []byte) {
switch level { switch level {
case 1: case 1:
return h1Tag, h1CloseTag return h1Tag, h1CloseTag
@ -619,7 +619,7 @@ func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkSt
// to be added and when not. // to be added and when not.
if node.Prev != nil { if node.Prev != nil {
switch node.Prev.Type { switch node.Prev.Type {
case HTMLBlock, List, Paragraph, Header, CodeBlock, BlockQuote, HorizontalRule: case HTMLBlock, List, Paragraph, Heading, CodeBlock, BlockQuote, HorizontalRule:
r.cr(w) r.cr(w)
} }
} }
@ -648,19 +648,19 @@ func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkSt
r.cr(w) r.cr(w)
r.out(w, node.Literal) r.out(w, node.Literal)
r.cr(w) r.cr(w)
case Header: case Heading:
openTag, closeTag := headerTagsFromLevel(node.Level) openTag, closeTag := headingTagsFromLevel(node.Level)
if entering { if entering {
if node.IsTitleblock { if node.IsTitleblock {
attrs = append(attrs, `class="title"`) attrs = append(attrs, `class="title"`)
} }
if node.HeaderID != "" { if node.HeadingID != "" {
id := r.ensureUniqueHeaderID(node.HeaderID) id := r.ensureUniqueHeadingID(node.HeadingID)
if r.HeaderIDPrefix != "" { if r.HeadingIDPrefix != "" {
id = r.HeaderIDPrefix + id id = r.HeadingIDPrefix + id
} }
if r.HeaderIDSuffix != "" { if r.HeadingIDSuffix != "" {
id = id + r.HeaderIDSuffix id = id + r.HeadingIDSuffix
} }
attrs = append(attrs, fmt.Sprintf(`id="%s"`, id)) attrs = append(attrs, fmt.Sprintf(`id="%s"`, id))
} }
@ -870,15 +870,15 @@ func (r *HTMLRenderer) writeDocumentHeader(w *bytes.Buffer) {
func (r *HTMLRenderer) writeTOC(w *bytes.Buffer, ast *Node) { func (r *HTMLRenderer) writeTOC(w *bytes.Buffer, ast *Node) {
buf := bytes.Buffer{} buf := bytes.Buffer{}
inHeader := false inHeading := false
tocLevel := 0 tocLevel := 0
headerCount := 0 headingCount := 0
ast.Walk(func(node *Node, entering bool) WalkStatus { ast.Walk(func(node *Node, entering bool) WalkStatus {
if node.Type == Header && !node.HeaderData.IsTitleblock { if node.Type == Heading && !node.HeadingData.IsTitleblock {
inHeader = entering inHeading = entering
if entering { if entering {
node.HeaderID = fmt.Sprintf("toc_%d", headerCount) node.HeadingID = fmt.Sprintf("toc_%d", headingCount)
if node.Level == tocLevel { if node.Level == tocLevel {
buf.WriteString("</li>\n\n<li>") buf.WriteString("</li>\n\n<li>")
} else if node.Level < tocLevel { } else if node.Level < tocLevel {
@ -894,15 +894,15 @@ func (r *HTMLRenderer) writeTOC(w *bytes.Buffer, ast *Node) {
} }
} }
fmt.Fprintf(&buf, `<a href="#toc_%d">`, headerCount) fmt.Fprintf(&buf, `<a href="#toc_%d">`, headingCount)
headerCount++ headingCount++
} else { } else {
buf.WriteString("</a>") buf.WriteString("</a>")
} }
return GoToNext return GoToNext
} }
if inHeader { if inHeading {
return r.RenderNode(&buf, node, entering) return r.RenderNode(&buf, node, entering)
} }

View File

@ -36,14 +36,14 @@ const (
Autolink // Detect embedded URLs that are not explicitly marked Autolink // Detect embedded URLs that are not explicitly marked
Strikethrough // Strikethrough text using ~~test~~ Strikethrough // Strikethrough text using ~~test~~
LaxHTMLBlocks // Loosen up HTML block parsing rules LaxHTMLBlocks // Loosen up HTML block parsing rules
SpaceHeaders // Be strict about prefix header rules SpaceHeadings // Be strict about prefix heading rules
HardLineBreak // Translate newlines into line breaks HardLineBreak // Translate newlines into line breaks
TabSizeEight // Expand tabs to eight spaces instead of four TabSizeEight // Expand tabs to eight spaces instead of four
Footnotes // Pandoc-style footnotes Footnotes // Pandoc-style footnotes
NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block
HeaderIDs // specify header IDs with {#id} HeadingIDs // specify heading IDs with {#id}
Titleblock // Titleblock ala pandoc Titleblock // Titleblock ala pandoc
AutoHeaderIDs // Create the header ID from the text AutoHeadingIDs // Create the heading ID from the text
BackslashLineBreak // Translate trailing backslashes into line breaks BackslashLineBreak // Translate trailing backslashes into line breaks
DefinitionLists // Render definition lists DefinitionLists // Render definition lists
@ -51,7 +51,7 @@ const (
SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes
CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode | CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode |
Autolink | Strikethrough | SpaceHeaders | HeaderIDs | Autolink | Strikethrough | SpaceHeadings | HeadingIDs |
BackslashLineBreak | DefinitionLists BackslashLineBreak | DefinitionLists
) )
@ -310,9 +310,9 @@ func MarkdownBasic(input []byte) []byte {
// //
// * Strikethrough support // * Strikethrough support
// //
// * Strict header parsing // * Strict heading parsing
// //
// * Custom Header IDs // * Custom Heading IDs
func MarkdownCommon(input []byte) []byte { func MarkdownCommon(input []byte) []byte {
// set up the HTML renderer // set up the HTML renderer
renderer := NewHTMLRenderer(HTMLRendererParameters{ renderer := NewHTMLRenderer(HTMLRendererParameters{
@ -392,7 +392,7 @@ func Parse(input []byte, opts Options) *Node {
} }
// Walk the tree again and process inline markdown in each block // Walk the tree again and process inline markdown in each block
p.doc.Walk(func(node *Node, entering bool) WalkStatus { p.doc.Walk(func(node *Node, entering bool) WalkStatus {
if node.Type == Paragraph || node.Type == Header || node.Type == TableCell { if node.Type == Paragraph || node.Type == Heading || node.Type == TableCell {
p.inline(node, node.content) p.inline(node, node.content)
node.content = nil node.content = nil
} }
@ -433,7 +433,7 @@ func (p *parser) parseRefsToAST() {
finalizeList(block) finalizeList(block)
p.tip = above p.tip = above
block.Walk(func(node *Node, entering bool) WalkStatus { block.Walk(func(node *Node, entering bool) WalkStatus {
if node.Type == Paragraph || node.Type == Header { if node.Type == Paragraph || node.Type == Heading {
p.inline(node, node.content) p.inline(node, node.content)
node.content = nil node.content = nil
} }

14
node.go
View File

@ -17,7 +17,7 @@ const (
List List
Item Item
Paragraph Paragraph
Header Heading
HorizontalRule HorizontalRule
Emph Emph
Strong Strong
@ -44,7 +44,7 @@ var nodeTypeNames = []string{
List: "List", List: "List",
Item: "Item", Item: "Item",
Paragraph: "Paragraph", Paragraph: "Paragraph",
Header: "Header", Heading: "Heading",
HorizontalRule: "HorizontalRule", HorizontalRule: "HorizontalRule",
Emph: "Emph", Emph: "Emph",
Strong: "Strong", Strong: "Strong",
@ -102,10 +102,10 @@ type TableCellData struct {
Align CellAlignFlags // This holds the value for align attribute Align CellAlignFlags // This holds the value for align attribute
} }
// HeaderData contains fields relevant to a Header node type. // HeadingData contains fields relevant to a Heading node type.
type HeaderData struct { type HeadingData struct {
Level int // This holds the heading level number Level int // This holds the heading level number
HeaderID string // This might hold header ID, if present HeadingID string // This might hold heading ID, if present
IsTitleblock bool // Specifies whether it's a title block IsTitleblock bool // Specifies whether it's a title block
} }
@ -122,7 +122,7 @@ type Node struct {
Literal []byte // Text contents of the leaf nodes Literal []byte // Text contents of the leaf nodes
HeaderData // Populated if Type is Header HeadingData // Populated if Type is Heading
ListData // Populated if Type is List ListData // Populated if Type is List
CodeBlockData // Populated if Type is CodeBlock CodeBlockData // Populated if Type is CodeBlock
LinkData // Populated if Type is Link LinkData // Populated if Type is Link
@ -211,7 +211,7 @@ func (n *Node) isContainer() bool {
fallthrough fallthrough
case Paragraph: case Paragraph:
fallthrough fallthrough
case Header: case Heading:
fallthrough fallthrough
case Emph: case Emph:
fallthrough fallthrough