From 7e96268fb01b4781ec7b62bcd40597368d3cdabd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E6=99=BA=E8=B6=85?= <1012112796@qq.com>
Date: Fri, 31 Jul 2020 00:27:23 +0800
Subject: [PATCH] Vendor update: github.com/yuin/goldmark v1.2.1 (#12377)

Thanks to @yuin

fix #12376
---
 go.mod                                        |   2 +-
 go.sum                                        |   2 +
 vendor/github.com/yuin/goldmark/README.md     |  14 +-
 .../yuin/goldmark/extension/table.go          | 202 +++++++++++++++---
 .../yuin/goldmark/extension/typographer.go    |   2 +-
 .../yuin/goldmark/parser/delimiter.go         |   9 +-
 .../yuin/goldmark/renderer/html/html.go       |   2 +-
 vendor/github.com/yuin/goldmark/util/util.go  |  37 ++++
 vendor/modules.txt                            |   2 +-
 9 files changed, 233 insertions(+), 39 deletions(-)

diff --git a/go.mod b/go.mod
index 0dafbeaeca..e3616a99fb 100644
--- a/go.mod
+++ b/go.mod
@@ -100,7 +100,7 @@ require (
 	github.com/urfave/cli v1.20.0
 	github.com/xanzy/go-gitlab v0.31.0
 	github.com/yohcop/openid-go v1.0.0
-	github.com/yuin/goldmark v1.1.32
+	github.com/yuin/goldmark v1.2.1
 	github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691
 	github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60
 	golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
diff --git a/go.sum b/go.sum
index 2bb1864dc3..159a5b5f79 100644
--- a/go.sum
+++ b/go.sum
@@ -715,6 +715,8 @@ github.com/yuin/goldmark v1.1.25 h1:isv+Q6HQAmmL2Ofcmg8QauBmDPlUUnSoNhEcC940Rds=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32 h1:5tjfNdR2ki3yYQ842+eX2sQHeiwpKJ0RnHO4IYOc4V8=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 h1:VWSxtAiQNh3zgHJpdpkpVYjTPqRE3P6UZCOPa1nRDio=
 github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691/go.mod h1:YLF3kDffRfUH/bTxOxHhV6lxwIB3Vfj91rEwNMS9MXo=
 github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 h1:gZucqLjL1eDzVWrXj4uiWeMbAopJlBR2mKQAsTGdPwo=
diff --git a/vendor/github.com/yuin/goldmark/README.md b/vendor/github.com/yuin/goldmark/README.md
index b0923c9301..8cf7c5a0eb 100644
--- a/vendor/github.com/yuin/goldmark/README.md
+++ b/vendor/github.com/yuin/goldmark/README.md
@@ -203,6 +203,18 @@ heading {#id .className attrName=attrValue}
 ============
 ```
 
+### Table extension
+The Table extension implements [Table(extension)](https://github.github.com/gfm/#tables-extension-), as
+defined in [GitHub Flavored Markdown Spec](https://github.github.com/gfm/).
+
+Specs are defined for XHTML, so specs use some deprecated attributes for HTML5.
+
+You can override alignment rendering method via options.
+
+| Functional option | Type | Description |
+| ----------------- | ---- | ----------- |
+| `extension.WithTableCellAlignMethod` | `extension.TableCellAlignMethod` | Option indicates how are table cells aligned. |
+
 ### Typographer extension
 
 The Typographer extension translates plain ASCII punctuation characters into typographic-punctuation HTML entities.
@@ -219,7 +231,7 @@ Default substitutions are:
 | `<<`       | `&laquo;` |
 | `>>`       | `&raquo;` |
 
-You can override the defualt substitutions via `extensions.WithTypographicSubstitutions`:
+You can override the default substitutions via `extensions.WithTypographicSubstitutions`:
 
 ```go
 markdown := goldmark.New(
diff --git a/vendor/github.com/yuin/goldmark/extension/table.go b/vendor/github.com/yuin/goldmark/extension/table.go
index 91ba331995..f0e994e838 100644
--- a/vendor/github.com/yuin/goldmark/extension/table.go
+++ b/vendor/github.com/yuin/goldmark/extension/table.go
@@ -15,7 +15,113 @@ import (
 	"github.com/yuin/goldmark/util"
 )
 
-var tableDelimRegexp = regexp.MustCompile(`^[\s\-\|\:]+$`)
+// TableCellAlignMethod indicates how are table cells aligned in HTML format.indicates how are table cells aligned in HTML format.
+type TableCellAlignMethod int
+
+const (
+	// TableCellAlignDefault renders alignments by default method.
+	// With XHTML, alignments are rendered as an align attribute.
+	// With HTML5, alignments are rendered as a style attribute.
+	TableCellAlignDefault TableCellAlignMethod = iota
+
+	// TableCellAlignAttribute renders alignments as an align attribute.
+	TableCellAlignAttribute
+
+	// TableCellAlignStyle renders alignments as a style attribute.
+	TableCellAlignStyle
+
+	// TableCellAlignNone does not care about alignments.
+	// If you using classes or other styles, you can add these attributes
+	// in an ASTTransformer.
+	TableCellAlignNone
+)
+
+// TableConfig struct holds options for the extension.
+type TableConfig struct {
+	html.Config
+
+	// TableCellAlignMethod indicates how are table celss aligned.
+	TableCellAlignMethod TableCellAlignMethod
+}
+
+// TableOption interface is a functional option interface for the extension.
+type TableOption interface {
+	renderer.Option
+	// SetTableOption sets given option to the extension.
+	SetTableOption(*TableConfig)
+}
+
+// NewTableConfig returns a new Config with defaults.
+func NewTableConfig() TableConfig {
+	return TableConfig{
+		Config:               html.NewConfig(),
+		TableCellAlignMethod: TableCellAlignDefault,
+	}
+}
+
+// SetOption implements renderer.SetOptioner.
+func (c *TableConfig) SetOption(name renderer.OptionName, value interface{}) {
+	switch name {
+	case optTableCellAlignMethod:
+		c.TableCellAlignMethod = value.(TableCellAlignMethod)
+	default:
+		c.Config.SetOption(name, value)
+	}
+}
+
+type withTableHTMLOptions struct {
+	value []html.Option
+}
+
+func (o *withTableHTMLOptions) SetConfig(c *renderer.Config) {
+	if o.value != nil {
+		for _, v := range o.value {
+			v.(renderer.Option).SetConfig(c)
+		}
+	}
+}
+
+func (o *withTableHTMLOptions) SetTableOption(c *TableConfig) {
+	if o.value != nil {
+		for _, v := range o.value {
+			v.SetHTMLOption(&c.Config)
+		}
+	}
+}
+
+// WithTableHTMLOptions is functional option that wraps goldmark HTMLRenderer options.
+func WithTableHTMLOptions(opts ...html.Option) TableOption {
+	return &withTableHTMLOptions{opts}
+}
+
+const optTableCellAlignMethod renderer.OptionName = "TableTableCellAlignMethod"
+
+type withTableCellAlignMethod struct {
+	value TableCellAlignMethod
+}
+
+func (o *withTableCellAlignMethod) SetConfig(c *renderer.Config) {
+	c.Options[optTableCellAlignMethod] = o.value
+}
+
+func (o *withTableCellAlignMethod) SetTableOption(c *TableConfig) {
+	c.TableCellAlignMethod = o.value
+}
+
+// WithTableCellAlignMethod is a functional option that indicates how are table cells aligned in HTML format.
+func WithTableCellAlignMethod(a TableCellAlignMethod) TableOption {
+	return &withTableCellAlignMethod{a}
+}
+
+func isTableDelim(bs []byte) bool {
+	for _, b := range bs {
+		if !(util.IsSpace(b) || b == '-' || b == '|' || b == ':') {
+			return false
+		}
+	}
+	return true
+}
+
 var tableDelimLeft = regexp.MustCompile(`^\s*\:\-+\s*$`)
 var tableDelimRight = regexp.MustCompile(`^\s*\-+\:\s*$`)
 var tableDelimCenter = regexp.MustCompile(`^\s*\:\-+\:\s*$`)
@@ -37,22 +143,31 @@ func (b *tableParagraphTransformer) Transform(node *gast.Paragraph, reader text.
 	if lines.Len() < 2 {
 		return
 	}
-	alignments := b.parseDelimiter(lines.At(1), reader)
-	if alignments == nil {
-		return
+	for i := 1; i < lines.Len(); i++ {
+		alignments := b.parseDelimiter(lines.At(i), reader)
+		if alignments == nil {
+			continue
+		}
+		header := b.parseRow(lines.At(i-1), alignments, true, reader)
+		if header == nil || len(alignments) != header.ChildCount() {
+			return
+		}
+		table := ast.NewTable()
+		table.Alignments = alignments
+		table.AppendChild(table, ast.NewTableHeader(header))
+		for j := i + 1; j < lines.Len(); j++ {
+			table.AppendChild(table, b.parseRow(lines.At(j), alignments, false, reader))
+		}
+		node.Lines().SetSliced(0, i-1)
+		node.Parent().InsertAfter(node.Parent(), node, table)
+		if node.Lines().Len() == 0 {
+			node.Parent().RemoveChild(node.Parent(), node)
+		} else {
+			last := node.Lines().At(i - 2)
+			last.Stop = last.Stop - 1 // trim last newline(\n)
+			node.Lines().Set(i-2, last)
+		}
 	}
-	header := b.parseRow(lines.At(0), alignments, true, reader)
-	if header == nil || len(alignments) != header.ChildCount() {
-		return
-	}
-	table := ast.NewTable()
-	table.Alignments = alignments
-	table.AppendChild(table, ast.NewTableHeader(header))
-	for i := 2; i < lines.Len(); i++ {
-		table.AppendChild(table, b.parseRow(lines.At(i), alignments, false, reader))
-	}
-	node.Parent().InsertBefore(node.Parent(), node, table)
-	node.Parent().RemoveChild(node.Parent(), node)
 }
 
 func (b *tableParagraphTransformer) parseRow(segment text.Segment, alignments []ast.Alignment, isHeader bool, reader text.Reader) *ast.TableRow {
@@ -100,7 +215,7 @@ func (b *tableParagraphTransformer) parseRow(segment text.Segment, alignments []
 
 func (b *tableParagraphTransformer) parseDelimiter(segment text.Segment, reader text.Reader) []ast.Alignment {
 	line := segment.Value(reader.Source())
-	if !tableDelimRegexp.Match(line) {
+	if !isTableDelim(line) {
 		return nil
 	}
 	cols := bytes.Split(line, []byte{'|'})
@@ -131,16 +246,16 @@ func (b *tableParagraphTransformer) parseDelimiter(segment text.Segment, reader
 // TableHTMLRenderer is a renderer.NodeRenderer implementation that
 // renders Table nodes.
 type TableHTMLRenderer struct {
-	html.Config
+	TableConfig
 }
 
 // NewTableHTMLRenderer returns a new TableHTMLRenderer.
-func NewTableHTMLRenderer(opts ...html.Option) renderer.NodeRenderer {
+func NewTableHTMLRenderer(opts ...TableOption) renderer.NodeRenderer {
 	r := &TableHTMLRenderer{
-		Config: html.NewConfig(),
+		TableConfig: NewTableConfig(),
 	}
 	for _, opt := range opts {
-		opt.SetHTMLOption(&r.Config)
+		opt.SetTableOption(&r.TableConfig)
 	}
 	return r
 }
@@ -281,14 +396,33 @@ func (r *TableHTMLRenderer) renderTableCell(w util.BufWriter, source []byte, nod
 		tag = "th"
 	}
 	if entering {
-		align := ""
+		fmt.Fprintf(w, "<%s", tag)
 		if n.Alignment != ast.AlignNone {
-			if _, ok := n.AttributeString("align"); !ok { // Skip align render if overridden
-				// TODO: "align" is deprecated. style="text-align:%s" instead?
-				align = fmt.Sprintf(` align="%s"`, n.Alignment.String())
+			amethod := r.TableConfig.TableCellAlignMethod
+			if amethod == TableCellAlignDefault {
+				if r.Config.XHTML {
+					amethod = TableCellAlignAttribute
+				} else {
+					amethod = TableCellAlignStyle
+				}
+			}
+			switch amethod {
+			case TableCellAlignAttribute:
+				if _, ok := n.AttributeString("align"); !ok { // Skip align render if overridden
+					fmt.Fprintf(w, ` align="%s"`, n.Alignment.String())
+				}
+			case TableCellAlignStyle:
+				v, ok := n.AttributeString("style")
+				var cob util.CopyOnWriteBuffer
+				if ok {
+					cob = util.NewCopyOnWriteBuffer(v.([]byte))
+					cob.AppendByte(';')
+				}
+				style := fmt.Sprintf("text-align:%s", n.Alignment.String())
+				cob.Append(util.StringToReadOnlyBytes(style))
+				n.SetAttributeString("style", cob.Bytes())
 			}
 		}
-		fmt.Fprintf(w, "<%s", tag)
 		if n.Attributes() != nil {
 			if tag == "td" {
 				html.RenderAttributes(w, n, TableTdCellAttributeFilter) // <td>
@@ -296,7 +430,7 @@ func (r *TableHTMLRenderer) renderTableCell(w util.BufWriter, source []byte, nod
 				html.RenderAttributes(w, n, TableThCellAttributeFilter) // <th>
 			}
 		}
-		fmt.Fprintf(w, "%s>", align)
+		_ = w.WriteByte('>')
 	} else {
 		fmt.Fprintf(w, "</%s>\n", tag)
 	}
@@ -304,16 +438,26 @@ func (r *TableHTMLRenderer) renderTableCell(w util.BufWriter, source []byte, nod
 }
 
 type table struct {
+	options []TableOption
 }
 
 // Table is an extension that allow you to use GFM tables .
-var Table = &table{}
+var Table = &table{
+	options: []TableOption{},
+}
+
+// NewTable returns a new extension with given options.
+func NewTable(opts ...TableOption) goldmark.Extender {
+	return &table{
+		options: opts,
+	}
+}
 
 func (e *table) Extend(m goldmark.Markdown) {
 	m.Parser().AddOptions(parser.WithParagraphTransformers(
 		util.Prioritized(NewTableParagraphTransformer(), 200),
 	))
 	m.Renderer().AddOptions(renderer.WithNodeRenderers(
-		util.Prioritized(NewTableHTMLRenderer(), 500),
+		util.Prioritized(NewTableHTMLRenderer(e.options...), 500),
 	))
 }
diff --git a/vendor/github.com/yuin/goldmark/extension/typographer.go b/vendor/github.com/yuin/goldmark/extension/typographer.go
index 8e95231006..2c34730944 100644
--- a/vendor/github.com/yuin/goldmark/extension/typographer.go
+++ b/vendor/github.com/yuin/goldmark/extension/typographer.go
@@ -223,7 +223,7 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser
 					if len(line) > 4 {
 						after = util.ToRune(line, 4)
 					}
-					if len(line) == 3 || unicode.IsSpace(after) || unicode.IsPunct(after) {
+					if len(line) == 3 || util.IsSpaceRune(after) || util.IsPunctRune(after) {
 						node := gast.NewString(s.Substitutions[Apostrophe])
 						node.SetCode(true)
 						block.Advance(1)
diff --git a/vendor/github.com/yuin/goldmark/parser/delimiter.go b/vendor/github.com/yuin/goldmark/parser/delimiter.go
index 612d7b7377..8259f62249 100644
--- a/vendor/github.com/yuin/goldmark/parser/delimiter.go
+++ b/vendor/github.com/yuin/goldmark/parser/delimiter.go
@@ -3,7 +3,6 @@ package parser
 import (
 	"fmt"
 	"strings"
-	"unicode"
 
 	"github.com/yuin/goldmark/ast"
 	"github.com/yuin/goldmark/text"
@@ -128,10 +127,10 @@ func ScanDelimiter(line []byte, before rune, min int, processor DelimiterProcess
 		}
 
 		canOpen, canClose := false, false
-		beforeIsPunctuation := unicode.IsPunct(before)
-		beforeIsWhitespace := unicode.IsSpace(before)
-		afterIsPunctuation := unicode.IsPunct(after)
-		afterIsWhitespace := unicode.IsSpace(after)
+		beforeIsPunctuation := util.IsPunctRune(before)
+		beforeIsWhitespace := util.IsSpaceRune(before)
+		afterIsPunctuation := util.IsPunctRune(after)
+		afterIsWhitespace := util.IsSpaceRune(after)
 
 		isLeft := !afterIsWhitespace &&
 			(!afterIsPunctuation || beforeIsWhitespace || beforeIsPunctuation)
diff --git a/vendor/github.com/yuin/goldmark/renderer/html/html.go b/vendor/github.com/yuin/goldmark/renderer/html/html.go
index 537a256feb..e545a736b7 100644
--- a/vendor/github.com/yuin/goldmark/renderer/html/html.go
+++ b/vendor/github.com/yuin/goldmark/renderer/html/html.go
@@ -564,7 +564,7 @@ func (r *Renderer) renderImage(w util.BufWriter, source []byte, node ast.Node, e
 		_, _ = w.Write(util.EscapeHTML(util.URLEscape(n.Destination, true)))
 	}
 	_, _ = w.WriteString(`" alt="`)
-	_, _ = w.Write(n.Text(source))
+	_, _ = w.Write(util.EscapeHTML(n.Text(source)))
 	_ = w.WriteByte('"')
 	if n.Title != nil {
 		_, _ = w.WriteString(` title="`)
diff --git a/vendor/github.com/yuin/goldmark/util/util.go b/vendor/github.com/yuin/goldmark/util/util.go
index ef113c4ae1..fc1438dc19 100644
--- a/vendor/github.com/yuin/goldmark/util/util.go
+++ b/vendor/github.com/yuin/goldmark/util/util.go
@@ -8,6 +8,7 @@ import (
 	"regexp"
 	"sort"
 	"strconv"
+	"unicode"
 	"unicode/utf8"
 )
 
@@ -27,6 +28,7 @@ func NewCopyOnWriteBuffer(buffer []byte) CopyOnWriteBuffer {
 }
 
 // Write writes given bytes to the buffer.
+// Write allocate new buffer and clears it at the first time.
 func (b *CopyOnWriteBuffer) Write(value []byte) {
 	if !b.copied {
 		b.buffer = make([]byte, 0, len(b.buffer)+20)
@@ -35,7 +37,20 @@ func (b *CopyOnWriteBuffer) Write(value []byte) {
 	b.buffer = append(b.buffer, value...)
 }
 
+// Append appends given bytes to the buffer.
+// Append copy buffer at the first time.
+func (b *CopyOnWriteBuffer) Append(value []byte) {
+	if !b.copied {
+		tmp := make([]byte, len(b.buffer), len(b.buffer)+20)
+		copy(tmp, b.buffer)
+		b.buffer = tmp
+		b.copied = true
+	}
+	b.buffer = append(b.buffer, value...)
+}
+
 // WriteByte writes the given byte to the buffer.
+// WriteByte allocate new buffer and clears it at the first time.
 func (b *CopyOnWriteBuffer) WriteByte(c byte) {
 	if !b.copied {
 		b.buffer = make([]byte, 0, len(b.buffer)+20)
@@ -44,6 +59,18 @@ func (b *CopyOnWriteBuffer) WriteByte(c byte) {
 	b.buffer = append(b.buffer, c)
 }
 
+// AppendByte appends given bytes to the buffer.
+// AppendByte copy buffer at the first time.
+func (b *CopyOnWriteBuffer) AppendByte(c byte) {
+	if !b.copied {
+		tmp := make([]byte, len(b.buffer), len(b.buffer)+20)
+		copy(tmp, b.buffer)
+		b.buffer = tmp
+		b.copied = true
+	}
+	b.buffer = append(b.buffer, c)
+}
+
 // Bytes returns bytes of this buffer.
 func (b *CopyOnWriteBuffer) Bytes() []byte {
 	return b.buffer
@@ -777,11 +804,21 @@ func IsPunct(c byte) bool {
 	return punctTable[c] == 1
 }
 
+// IsPunct returns true if the given rune is a punctuation, otherwise false.
+func IsPunctRune(r rune) bool {
+	return int32(r) <= 256 && IsPunct(byte(r)) || unicode.IsPunct(r)
+}
+
 // IsSpace returns true if the given character is a space, otherwise false.
 func IsSpace(c byte) bool {
 	return spaceTable[c] == 1
 }
 
+// IsSpace returns true if the given rune is a space, otherwise false.
+func IsSpaceRune(r rune) bool {
+	return int32(r) <= 256 && IsSpace(byte(r)) || unicode.IsSpace(r)
+}
+
 // IsNumeric returns true if the given character is a numeric, otherwise false.
 func IsNumeric(c byte) bool {
 	return c >= '0' && c <= '9'
diff --git a/vendor/modules.txt b/vendor/modules.txt
index c9e9e241ea..ec09b5fc68 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -715,7 +715,7 @@ github.com/xi2/xz
 # github.com/yohcop/openid-go v1.0.0
 ## explicit
 github.com/yohcop/openid-go
-# github.com/yuin/goldmark v1.1.32
+# github.com/yuin/goldmark v1.2.1
 ## explicit
 github.com/yuin/goldmark
 github.com/yuin/goldmark/ast