diff --git a/go.mod b/go.mod
index 83a38fccd..8d1e15efe 100644
--- a/go.mod
+++ b/go.mod
@@ -67,7 +67,7 @@ require (
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/golang/glog v1.2.5 // indirect
github.com/golang/protobuf v1.5.4 // indirect
- github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 // indirect
+ github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/cel-go v0.26.0 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
diff --git a/go.sum b/go.sum
index b6d3646ee..fe0e3b9bc 100644
--- a/go.sum
+++ b/go.sum
@@ -130,8 +130,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 h1:4gjrh/PN2MuWCCElk8/I4OCKRKWCCo2zEct3VKCbibU=
-github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
+github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab h1:VYNivV7P8IRHUam2swVUNkhIdp0LRRFKe4hXNnoZKTc=
+github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI=
diff --git a/vendor/github.com/gomarkdown/markdown/html/renderer.go b/vendor/github.com/gomarkdown/markdown/html/renderer.go
index 494e7540b..8e2c1d1dc 100644
--- a/vendor/github.com/gomarkdown/markdown/html/renderer.go
+++ b/vendor/github.com/gomarkdown/markdown/html/renderer.go
@@ -641,14 +641,29 @@ func (r *Renderer) EnsureUniqueHeadingID(id string) string {
return id
}
-func (r *Renderer) headingEnter(w io.Writer, nodeData *ast.Heading) {
+func (r *Renderer) MakeUniqueHeadingID(hdr *ast.Heading) string {
+ if hdr.HeadingID == "" {
+ return ""
+ }
+ id := r.EnsureUniqueHeadingID(hdr.HeadingID)
+ if r.Opts.HeadingIDPrefix != "" {
+ id = r.Opts.HeadingIDPrefix + id
+ }
+ if r.Opts.HeadingIDSuffix != "" {
+ id = id + r.Opts.HeadingIDSuffix
+ }
+ hdr.HeadingID = id
+ return id
+}
+
+func (r *Renderer) HeadingEnter(w io.Writer, hdr *ast.Heading) {
var attrs []string
var class string
// TODO(miek): add helper functions for coalescing these classes.
- if nodeData.IsTitleblock {
+ if hdr.IsTitleblock {
class = "title"
}
- if nodeData.IsSpecial {
+ if hdr.IsSpecial {
if class != "" {
class += " special"
} else {
@@ -659,35 +674,29 @@ func (r *Renderer) headingEnter(w io.Writer, nodeData *ast.Heading) {
attrs = []string{`class="` + class + `"`}
}
- if nodeData.HeadingID != "" {
- id := r.EnsureUniqueHeadingID(nodeData.HeadingID)
- if r.Opts.HeadingIDPrefix != "" {
- id = r.Opts.HeadingIDPrefix + id
- }
- if r.Opts.HeadingIDSuffix != "" {
- id = id + r.Opts.HeadingIDSuffix
- }
+ if hdr.HeadingID != "" {
+ id := r.MakeUniqueHeadingID(hdr)
attrID := `id="` + id + `"`
attrs = append(attrs, attrID)
}
- attrs = append(attrs, BlockAttrs(nodeData)...)
+ attrs = append(attrs, BlockAttrs(hdr)...)
r.CR(w)
- r.OutTag(w, HeadingOpenTagFromLevel(nodeData.Level), attrs)
+ r.OutTag(w, HeadingOpenTagFromLevel(hdr.Level), attrs)
}
-func (r *Renderer) headingExit(w io.Writer, heading *ast.Heading) {
- r.Outs(w, HeadingCloseTagFromLevel(heading.Level))
- if !(IsListItem(heading.Parent) && ast.GetNextNode(heading) == nil) {
+func (r *Renderer) HeadingExit(w io.Writer, hdr *ast.Heading) {
+ r.Outs(w, HeadingCloseTagFromLevel(hdr.Level))
+ if !(IsListItem(hdr.Parent) && ast.GetNextNode(hdr) == nil) {
r.CR(w)
}
}
// Heading writes ast.Heading node
-func (r *Renderer) Heading(w io.Writer, node *ast.Heading, entering bool) {
+func (r *Renderer) Heading(w io.Writer, hdr *ast.Heading, entering bool) {
if entering {
- r.headingEnter(w, node)
+ r.HeadingEnter(w, hdr)
} else {
- r.headingExit(w, node)
+ r.HeadingExit(w, hdr)
}
}
diff --git a/vendor/github.com/gomarkdown/markdown/parser/block.go b/vendor/github.com/gomarkdown/markdown/parser/block.go
index 4b7326e7d..e0b99604e 100644
--- a/vendor/github.com/gomarkdown/markdown/parser/block.go
+++ b/vendor/github.com/gomarkdown/markdown/parser/block.go
@@ -76,6 +76,7 @@ var (
"output": {},
"progress": {},
"section": {},
+ "svg": {},
"video": {},
}
)
@@ -925,7 +926,7 @@ func syntaxRange(data []byte, iout *int) (int, int) {
i++
} else {
- for i < n && !IsSpace(data[i]) {
+ for i < n && data[i] != '\n' {
syn++
i++
}
@@ -950,8 +951,6 @@ func (p *Parser) fencedCodeBlock(data []byte, doRender bool) int {
work.WriteByte('\n')
for {
- // safe to assume beg < len(data)
-
// check for the end of the code block
fenceEnd, _ := isFenceLine(data[beg:], nil, marker)
if fenceEnd != 0 {
@@ -968,48 +967,47 @@ func (p *Parser) fencedCodeBlock(data []byte, doRender bool) int {
}
// verbatim copy to the working buffer
- if doRender {
- work.Write(data[beg:end])
- }
+ work.Write(data[beg:end])
beg = end
}
- if doRender {
- codeBlock := &ast.CodeBlock{
- IsFenced: true,
- }
- codeBlock.Content = work.Bytes() // TODO: get rid of temp buffer
+ if !doRender {
+ return beg
+ }
+ codeBlock := &ast.CodeBlock{
+ IsFenced: true,
+ }
+ codeBlock.Content = work.Bytes() // TODO: get rid of temp buffer
- if p.extensions&Mmark == 0 {
- p.AddBlock(codeBlock)
- finalizeCodeBlock(codeBlock)
- return beg
- }
-
- // Check for caption and if found make it a figure.
- if captionContent, id, consumed := p.caption(data[beg:], []byte(captionFigure)); consumed > 0 {
- figure := &ast.CaptionFigure{}
- caption := &ast.Caption{}
- figure.HeadingID = id
- p.Inline(caption, captionContent)
-
- p.AddBlock(figure)
- codeBlock.AsLeaf().Attribute = figure.AsContainer().Attribute
- p.addChild(codeBlock)
- finalizeCodeBlock(codeBlock)
- p.addChild(caption)
- p.Finalize(figure)
-
- beg += consumed
-
- return beg
- }
-
- // Still here, normal block
+ if p.extensions&Mmark == 0 {
p.AddBlock(codeBlock)
finalizeCodeBlock(codeBlock)
+ return beg
}
+ // Check for caption and if found make it a figure.
+ if captionContent, id, consumed := p.caption(data[beg:], []byte(captionFigure)); consumed > 0 {
+ figure := &ast.CaptionFigure{}
+ caption := &ast.Caption{}
+ figure.HeadingID = id
+ p.Inline(caption, captionContent)
+
+ p.AddBlock(figure)
+ codeBlock.AsLeaf().Attribute = figure.AsContainer().Attribute
+ p.addChild(codeBlock)
+ finalizeCodeBlock(codeBlock)
+ p.addChild(caption)
+ p.Finalize(figure)
+
+ beg += consumed
+
+ return beg
+ }
+
+ // Still here, normal block
+ p.AddBlock(codeBlock)
+ finalizeCodeBlock(codeBlock)
+
return beg
}
@@ -1352,6 +1350,7 @@ func finalizeList(list *ast.List) {
// Parse a single list item.
// Assumes initial prefix is already removed if this is a sublist.
func (p *Parser) listItem(data []byte, flags *ast.ListType) int {
+ isDefinitionList := *flags&ast.ListTypeDefinition != 0
// keep track of the indentation of the first line
itemIndent := 0
if data[0] == '\t' {
@@ -1384,7 +1383,7 @@ func (p *Parser) listItem(data []byte, flags *ast.ListType) int {
}
if i == 0 {
// if in definition list, set term flag and continue
- if *flags&ast.ListTypeDefinition != 0 {
+ if isDefinitionList {
*flags |= ast.ListTypeTerm
} else {
return 0
@@ -1410,6 +1409,9 @@ func (p *Parser) listItem(data []byte, flags *ast.ListType) int {
// process the following lines
containsBlankLine := false
sublist := 0
+ // track fenced code blocks inside list items so that lines within
+ // the fence are gathered verbatim (not misinterpreted as list items)
+ fenceMarker := ""
gatherlines:
for line < len(data) {
@@ -1443,9 +1445,49 @@ gatherlines:
chunk := data[line+indentIndex : i]
+ // track fenced code blocks inside list items;
+ // only track fences that are indented (part of the list item content),
+ // a fence at indent 0 ends the list (handled below)
+ if !isDefinitionList && p.extensions&FencedCode != 0 {
+ if fenceMarker != "" {
+ if indent == 0 {
+ // non-indented line while inside a fence means we
+ // left the list item content -- abandon the fence
+ fenceMarker = ""
+ } else {
+ // inside a fence: check for closing fence
+ _, marker := isFenceLine(chunk, nil, fenceMarker)
+ if marker != "" {
+ fenceMarker = ""
+ }
+ // gather the line verbatim, skip structure detection
+ if containsBlankLine {
+ containsBlankLine = false
+ raw.WriteByte('\n')
+ }
+ raw.Write(chunk)
+ line = i
+ continue
+ }
+ } else if indent > 0 {
+ // not inside a fence: check for opening fence (indented only)
+ _, marker := isFenceLine(chunk, nil, "")
+ if marker != "" {
+ fenceMarker = marker
+ }
+ }
+ }
+
// If there is a fence line (marking starting of a code block)
// without indent do not process it as part of the list.
- if p.extensions&FencedCode != 0 {
+ //
+ // does not apply for definition lists because it causes infinite
+ // loop if text before defintion term is fenced code block start
+ // marker but not part of actual fenced code block
+ // for defnition lists we're called after parsing fence code blocks
+ // so we kno this cannot be a fenced block
+ // https://github.com/gomarkdown/markdown/issues/326
+ if !isDefinitionList && p.extensions&FencedCode != 0 {
fenceLineEnd, _ := isFenceLine(chunk, nil, "")
if fenceLineEnd > 0 && indent == 0 {
*flags |= ast.ListItemEndOfList
@@ -1652,7 +1694,9 @@ func (p *Parser) paragraph(data []byte) int {
if p.extensions&DefinitionLists != 0 {
if i < len(data)-1 && data[i+1] == ':' {
listLen := p.list(data[prev:], ast.ListTypeDefinition, 0, '.')
- return prev + listLen
+ if listLen > 0 {
+ return prev + listLen
+ }
}
}
diff --git a/vendor/github.com/gomarkdown/markdown/parser/citation.go b/vendor/github.com/gomarkdown/markdown/parser/citation.go
index 217d4def0..5790e22a8 100644
--- a/vendor/github.com/gomarkdown/markdown/parser/citation.go
+++ b/vendor/github.com/gomarkdown/markdown/parser/citation.go
@@ -49,6 +49,9 @@ func citation(p *Parser, data []byte, offset int) (int, ast.Node) {
for _, citation := range citations {
var suffix []byte
citation = bytes.TrimSpace(citation)
+ if len(citation) == 0 {
+ continue
+ }
j := 0
if citation[j] != '@' {
// not a citation, drop out entirely.
diff --git a/vendor/github.com/gomarkdown/markdown/parser/inline.go b/vendor/github.com/gomarkdown/markdown/parser/inline.go
index d6c8a7204..23a53e384 100644
--- a/vendor/github.com/gomarkdown/markdown/parser/inline.go
+++ b/vendor/github.com/gomarkdown/markdown/parser/inline.go
@@ -271,7 +271,7 @@ func maybeInlineFootnoteOrSuper(p *Parser, data []byte, offset int) (int, ast.No
// '[': parse a link or an image or a footnote or a citation
func link(p *Parser, data []byte, offset int) (int, ast.Node) {
// no links allowed inside regular links, footnote, and deferred footnotes
- if p.insideLink && (offset > 0 && data[offset-1] == '[' || len(data)-1 > offset && data[offset+1] == '^') {
+ if p.InsideLink && (offset > 0 && data[offset-1] == '[' || len(data)-1 > offset && data[offset+1] == '^') {
return 0, nil
}
@@ -362,25 +362,27 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) {
linkB := i
brace := 0
+ var c byte
// look for link end: ' " )
findlinkend:
for i < len(data) {
+ c = data[i]
switch {
- case data[i] == '\\':
+ case c == '\\':
i += 2
- case data[i] == '(':
+ case c == '(':
brace++
i++
- case data[i] == ')':
+ case c == ')':
if brace <= 0 {
break findlinkend
}
brace--
i++
- case data[i] == '\'' || data[i] == '"':
+ case c == '\'' || c == '"':
break findlinkend
default:
@@ -402,14 +404,15 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) {
findtitleend:
for i < len(data) {
+ c = data[i]
switch {
- case data[i] == '\\':
+ case c == '\\':
i++
- case data[i] == data[titleB-1]: // matching title delimiter
+ case c == data[titleB-1]: // matching title delimiter
titleEndCharFound = true
- case titleEndCharFound && data[i] == ')':
+ case titleEndCharFound && c == ')':
break findtitleend
}
i++
@@ -619,10 +622,10 @@ func link(p *Parser, data []byte, offset int) (int, ast.Node) {
} else {
// links cannot contain other links, so turn off link parsing
// temporarily and recurse
- insideLink := p.insideLink
- p.insideLink = true
+ InsideLink := p.InsideLink
+ p.InsideLink = true
p.Inline(link, data[1:txtE])
- p.insideLink = insideLink
+ p.InsideLink = InsideLink
}
return i, link
@@ -736,7 +739,7 @@ func leftAngle(p *Parser, data []byte, offset int) (int, ast.Node) {
}
// '\\' backslash escape
-var escapeChars = []byte("\\`*_{}[]()#+-.!:|&<>~^$")
+var EscapeChars = []byte("\\`*_{}[]()#+-.!:|&<>~^$")
func escape(p *Parser, data []byte, offset int) (int, ast.Node) {
data = data[offset:]
@@ -753,7 +756,7 @@ func escape(p *Parser, data []byte, offset int) (int, ast.Node) {
return 2, &ast.Hardbreak{}
}
- if bytes.IndexByte(escapeChars, data[1]) < 0 {
+ if bytes.IndexByte(EscapeChars, data[1]) < 0 {
return 0, nil
}
@@ -814,7 +817,12 @@ func entity(p *Parser, data []byte, offset int) (int, ast.Node) {
codepoint, err = strconv.ParseUint(string(ent[2:len(ent)-1]), 10, 64)
}
if err == nil { // only if conversion was valid return here.
- return end, newTextNode([]byte(string(rune(codepoint))))
+ r := rune(codepoint)
+ // Replace invalid codepoints with U+FFFD per CommonMark spec section 6.2
+ if r == 0 || (r >= 0xD800 && r <= 0xDFFF) || r > 0x10FFFF {
+ r = '\uFFFD'
+ }
+ return end, newTextNode([]byte(string(r)))
}
return end, newTextNode(ent)
@@ -857,7 +865,7 @@ const shortestPrefix = 6 // len("ftp://"), the shortest of the above
func maybeAutoLink(p *Parser, data []byte, offset int) (int, ast.Node) {
// quick check to rule out most false hits
- if p.insideLink || len(data) < offset+shortestPrefix {
+ if p.InsideLink || len(data) < offset+shortestPrefix {
return 0, nil
}
for _, prefix := range protocolPrefixes {
@@ -1070,10 +1078,11 @@ func tagLength(data []byte) (autolink autolinkType, end int) {
// one of the forbidden chars has been found
autolink = notAutolink
}
- i += bytes.IndexByte(data[i:], '>')
- if i < 0 {
+ j = bytes.IndexByte(data[i:], '>')
+ if j < 0 {
return autolink, 0
}
+ i += j
return autolink, i + 1
}
@@ -1185,30 +1194,30 @@ func helperFindEmphChar(data []byte, c byte) int {
func helperEmphasis(p *Parser, data []byte, c byte) (int, ast.Node) {
i := 0
- // skip one symbol if coming from emph3
+ // skip two symbol if coming from emph3, as it detected a double emphasis case
if len(data) > 1 && data[0] == c && data[1] == c {
- i = 1
+ i = 2
}
for i < len(data) {
length := helperFindEmphChar(data[i:], c)
- if length == 0 {
- return 0, nil
- }
i += length
if i >= len(data) {
return 0, nil
}
if i+1 < len(data) && data[i+1] == c {
- i++
+ i += 2
continue
}
if data[i] == c && !IsSpace(data[i-1]) {
-
if p.extensions&NoIntraEmphasis != 0 {
- if !(i+1 == len(data) || IsSpace(data[i+1]) || IsPunctuation(data[i+1])) {
+ rest := data[i+1:]
+ if !(len(rest) == 0 || IsSpace(rest[0]) || IsPunctuation2(rest)) {
+ if length == 0 {
+ return 0, nil
+ }
continue
}
}
@@ -1217,6 +1226,11 @@ func helperEmphasis(p *Parser, data []byte, c byte) (int, ast.Node) {
p.Inline(emph, data[:i])
return i + 1, emph
}
+
+ // We have to check this at the end, otherwise the scenario where we find repeated c's will get skipped
+ if length == 0 {
+ return 0, nil
+ }
}
return 0, nil
@@ -1233,18 +1247,53 @@ func helperDoubleEmphasis(p *Parser, data []byte, c byte) (int, ast.Node) {
i += length
if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !IsSpace(data[i-1]) {
+ // When the closing delimiter is *** (3+ chars) and there is an
+ // unclosed single emphasis opener inside the content, include
+ // one extra char in the content so that the inner emphasis can
+ // pair with it. For example: **bold *ital*** should produce
+ // bold ital, not bold *ital*.
+ // See https://github.com/gomarkdown/markdown/issues/279
+ contentEnd := i
+ if i+2 < len(data) && data[i+2] == c && c != '~' {
+ if hasTrailingEmphOpener(data[:i], c) {
+ contentEnd = i + 1
+ }
+ }
+
var node ast.Node = &ast.Strong{}
if c == '~' {
node = &ast.Del{}
}
- p.Inline(node, data[:i])
- return i + 2, node
+ p.Inline(node, data[:contentEnd])
+ return contentEnd + 2, node
}
i++
}
return 0, nil
}
+// hasTrailingEmphOpener checks if the last occurrence of c in data is an
+// unclosed opener. An opener is c preceded by whitespace or start of data,
+// followed by non-whitespace. If the last c is a closer (preceded by
+// non-whitespace), the emphasis pair is balanced and we should not shift
+// the content boundary.
+func hasTrailingEmphOpener(data []byte, c byte) bool {
+ // find the last c in data
+ last := -1
+ for j := len(data) - 1; j >= 0; j-- {
+ if data[j] == c {
+ last = j
+ break
+ }
+ }
+ if last < 0 {
+ return false
+ }
+ // opener: preceded by space/start, followed by non-space
+ return (last == 0 || IsSpace(data[last-1])) &&
+ last+1 < len(data) && !IsSpace(data[last+1])
+}
+
func helperTripleEmphasis(p *Parser, data []byte, offset int, c byte) (int, ast.Node) {
i := 0
origData := data
diff --git a/vendor/github.com/gomarkdown/markdown/parser/parser.go b/vendor/github.com/gomarkdown/markdown/parser/parser.go
index f0a0d9cd9..43f213692 100644
--- a/vendor/github.com/gomarkdown/markdown/parser/parser.go
+++ b/vendor/github.com/gomarkdown/markdown/parser/parser.go
@@ -8,6 +8,8 @@ import (
"fmt"
"strconv"
"strings"
+ "unicode"
+ "unicode/utf8"
"github.com/gomarkdown/markdown/ast"
)
@@ -56,7 +58,7 @@ const (
)
// for each character that triggers a response when parsing inline data.
-type inlineParser func(p *Parser, data []byte, offset int) (int, ast.Node)
+type InlineParser func(p *Parser, data []byte, offset int) (int, ast.Node)
// ReferenceOverrideFunc is expected to be called with a reference string and
// return either a valid Reference type that the reference string maps to or
@@ -98,10 +100,10 @@ type Parser struct {
refs map[string]*reference
refsRecord map[string]struct{}
- inlineCallback [256]inlineParser
+ inlineCallback [256]InlineParser
nesting int
maxNesting int
- insideLink bool
+ InsideLink bool
indexCnt int // incremented after every index
// Footnotes need to be ordered as well as available to quickly check for
@@ -122,6 +124,8 @@ type Parser struct {
// collect headings where we auto-generated id so that we can
// ensure they are unique at the end
allHeadingsWithAutoID []*ast.Heading
+
+ didParse bool
}
// New creates a markdown parser with CommonExtensions.
@@ -138,8 +142,8 @@ func NewWithExtensions(extension Extensions) *Parser {
p := Parser{
refs: make(map[string]*reference),
refsRecord: make(map[string]struct{}),
- maxNesting: 16,
- insideLink: false,
+ maxNesting: 64,
+ InsideLink: false,
Doc: &ast.Document{},
extensions: extension,
allClosed: true,
@@ -181,7 +185,7 @@ func NewWithExtensions(extension Extensions) *Parser {
return &p
}
-func (p *Parser) RegisterInline(n byte, fn inlineParser) inlineParser {
+func (p *Parser) RegisterInline(n byte, fn InlineParser) InlineParser {
prev := p.inlineCallback[n]
p.inlineCallback[n] = fn
return prev
@@ -290,7 +294,14 @@ type Reference struct {
//
// You can then convert AST to html using html.Renderer, to some other format
// using a custom renderer or transform the tree.
+//
+// Parser is not reusable. Create a new Parser for each Parse() call.
func (p *Parser) Parse(input []byte) ast.Node {
+ if p.didParse {
+ panic("Parser is not reusable. Must create new Parser for each Parse() call.")
+ }
+ p.didParse = true
+
// the code only works with Unix CR newlines so to make life easy for
// callers normalize newlines
input = NormalizeNewlines(input)
@@ -727,7 +738,21 @@ func IsPunctuation(c byte) bool {
return false
}
-// IsSpace returns true if c is a white-space charactr
+func IsPunctuation2(d []byte) bool {
+ if len(d) == 0 {
+ return false
+ }
+ if IsPunctuation(d[0]) {
+ return true
+ }
+ r, _ := utf8.DecodeRune(d)
+ if r == utf8.RuneError {
+ return false
+ }
+ return unicode.IsPunct(r)
+}
+
+// IsSpace returns true if c is a white-space character
func IsSpace(c byte) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'
}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index ead692d5f..5db07718c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -103,7 +103,7 @@ github.com/golang/glog/internal/stackdump
# github.com/golang/protobuf v1.5.4
## explicit; go 1.17
github.com/golang/protobuf/proto
-# github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0
+# github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab
## explicit; go 1.12
github.com/gomarkdown/markdown/ast
github.com/gomarkdown/markdown/html