Source File
html.go
Belonging Package
github.com/yuin/goldmark/renderer/html
package html
import (
)
func ( *Config) ( renderer.OptionName, interface{}) {
switch {
case optHardWraps:
.HardWraps = .(bool)
case optXHTML:
.XHTML = .(bool)
case optUnsafe:
.Unsafe = .(bool)
case optTextWriter:
.Writer = .(Writer)
}
}
const optTextWriter renderer.OptionName = "Writer"
type withWriter struct {
value Writer
}
func ( *withWriter) ( *renderer.Config) {
.Options[optTextWriter] = .value
}
func ( *withWriter) ( *Config) {
.Writer = .value
}
func ( Writer) interface {
renderer.Option
Option
} {
return &withWriter{}
}
const optHardWraps renderer.OptionName = "HardWraps"
type withHardWraps struct {
}
func ( *withHardWraps) ( *renderer.Config) {
.Options[optHardWraps] = true
}
func ( *withHardWraps) ( *Config) {
.HardWraps = true
}
func () interface {
renderer.Option
Option
} {
return &withHardWraps{}
}
const optUnsafe renderer.OptionName = "Unsafe"
type withUnsafe struct {
}
func ( *withUnsafe) ( *renderer.Config) {
.Options[optUnsafe] = true
}
func ( *withUnsafe) ( *Config) {
.Unsafe = true
}
func () interface {
renderer.Option
Option
} {
return &withUnsafe{}
}
func ( ...Option) renderer.NodeRenderer {
:= &Renderer{
Config: NewConfig(),
}
for , := range {
.SetHTMLOption(&.Config)
}
return
}
.Register(ast.KindDocument, .renderDocument)
.Register(ast.KindHeading, .renderHeading)
.Register(ast.KindBlockquote, .renderBlockquote)
.Register(ast.KindCodeBlock, .renderCodeBlock)
.Register(ast.KindFencedCodeBlock, .renderFencedCodeBlock)
.Register(ast.KindHTMLBlock, .renderHTMLBlock)
.Register(ast.KindList, .renderList)
.Register(ast.KindListItem, .renderListItem)
.Register(ast.KindParagraph, .renderParagraph)
.Register(ast.KindTextBlock, .renderTextBlock)
.Register(ast.KindThematicBreak, .renderThematicBreak)
.Register(ast.KindAutoLink, .renderAutoLink)
.Register(ast.KindCodeSpan, .renderCodeSpan)
.Register(ast.KindEmphasis, .renderEmphasis)
.Register(ast.KindImage, .renderImage)
.Register(ast.KindLink, .renderLink)
.Register(ast.KindRawHTML, .renderRawHTML)
.Register(ast.KindText, .renderText)
.Register(ast.KindString, .renderString)
}
func ( *Renderer) ( util.BufWriter, []byte, ast.Node) {
:= .Lines().Len()
for := 0; < ; ++ {
:= .Lines().At()
.Writer.RawWrite(, .Value())
}
}
var GlobalAttributeFilter = util.NewBytesFilter(
[]byte("accesskey"),
[]byte("autocapitalize"),
[]byte("class"),
[]byte("contenteditable"),
[]byte("contextmenu"),
[]byte("dir"),
[]byte("draggable"),
[]byte("dropzone"),
[]byte("hidden"),
[]byte("id"),
[]byte("itemprop"),
[]byte("lang"),
[]byte("slot"),
[]byte("spellcheck"),
[]byte("style"),
[]byte("tabindex"),
[]byte("title"),
[]byte("translate"),
)
return ast.WalkContinue, nil
}
var HeadingAttributeFilter = GlobalAttributeFilter
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
:= .(*ast.Heading)
if {
_, _ = .WriteString("<h")
_ = .WriteByte("0123456"[.Level])
if .Attributes() != nil {
RenderAttributes(, , HeadingAttributeFilter)
}
_ = .WriteByte('>')
} else {
_, _ = .WriteString("</h")
_ = .WriteByte("0123456"[.Level])
_, _ = .WriteString(">\n")
}
return ast.WalkContinue, nil
}
var BlockquoteAttributeFilter = GlobalAttributeFilter.Extend(
[]byte("cite"),
)
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if {
if .Attributes() != nil {
_, _ = .WriteString("<blockquote")
RenderAttributes(, , BlockquoteAttributeFilter)
_ = .WriteByte('>')
} else {
_, _ = .WriteString("<blockquote>\n")
}
} else {
_, _ = .WriteString("</blockquote>\n")
}
return ast.WalkContinue, nil
}
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if {
_, _ = .WriteString("<pre><code>")
.writeLines(, , )
} else {
_, _ = .WriteString("</code></pre>\n")
}
return ast.WalkContinue, nil
}
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
:= .(*ast.FencedCodeBlock)
if {
_, _ = .WriteString("<pre><code")
:= .Language()
if != nil {
_, _ = .WriteString(" class=\"language-")
.Writer.Write(, )
_, _ = .WriteString("\"")
}
_ = .WriteByte('>')
.writeLines(, , )
} else {
_, _ = .WriteString("</code></pre>\n")
}
return ast.WalkContinue, nil
}
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
:= .(*ast.HTMLBlock)
if {
if .Unsafe {
:= .Lines().Len()
for := 0; < ; ++ {
:= .Lines().At()
_, _ = .Write(.Value())
}
} else {
_, _ = .WriteString("<!-- raw HTML omitted -->\n")
}
} else {
if .HasClosure() {
if .Unsafe {
:= .ClosureLine
_, _ = .Write(.Value())
} else {
_, _ = .WriteString("<!-- raw HTML omitted -->\n")
}
}
}
return ast.WalkContinue, nil
}
var ListAttributeFilter = GlobalAttributeFilter.Extend(
[]byte("start"),
[]byte("reversed"),
[]byte("type"),
)
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
:= .(*ast.List)
:= "ul"
if .IsOrdered() {
= "ol"
}
if {
_ = .WriteByte('<')
_, _ = .WriteString()
if .IsOrdered() && .Start != 1 {
fmt.Fprintf(, " start=\"%d\"", .Start)
}
if .Attributes() != nil {
RenderAttributes(, , ListAttributeFilter)
}
_, _ = .WriteString(">\n")
} else {
_, _ = .WriteString("</")
_, _ = .WriteString()
_, _ = .WriteString(">\n")
}
return ast.WalkContinue, nil
}
var ListItemAttributeFilter = GlobalAttributeFilter.Extend(
[]byte("value"),
)
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if {
if .Attributes() != nil {
_, _ = .WriteString("<li")
RenderAttributes(, , ListItemAttributeFilter)
_ = .WriteByte('>')
} else {
_, _ = .WriteString("<li>")
}
:= .FirstChild()
if != nil {
if , := .(*ast.TextBlock); ! {
_ = .WriteByte('\n')
}
}
} else {
_, _ = .WriteString("</li>\n")
}
return ast.WalkContinue, nil
}
var ParagraphAttributeFilter = GlobalAttributeFilter
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if {
if .Attributes() != nil {
_, _ = .WriteString("<p")
RenderAttributes(, , ParagraphAttributeFilter)
_ = .WriteByte('>')
} else {
_, _ = .WriteString("<p>")
}
} else {
_, _ = .WriteString("</p>\n")
}
return ast.WalkContinue, nil
}
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if ! {
if , := .NextSibling().(ast.Node); && .FirstChild() != nil {
_ = .WriteByte('\n')
}
}
return ast.WalkContinue, nil
}
var ThematicAttributeFilter = GlobalAttributeFilter.Extend(
[]byte("align"), // [Deprecated]
[]byte("color"), // [Not Standardized]
[]byte("noshade"), // [Deprecated]
[]byte("size"), // [Deprecated]
[]byte("width"), // [Deprecated]
)
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if ! {
return ast.WalkContinue, nil
}
_, _ = .WriteString("<hr")
if .Attributes() != nil {
RenderAttributes(, , ThematicAttributeFilter)
}
if .XHTML {
_, _ = .WriteString(" />\n")
} else {
_, _ = .WriteString(">\n")
}
return ast.WalkContinue, nil
}
[]byte("hreflang"),
[]byte("media"),
[]byte("ping"),
[]byte("referrerpolicy"),
[]byte("rel"),
[]byte("shape"),
[]byte("target"),
)
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
:= .(*ast.AutoLink)
if ! {
return ast.WalkContinue, nil
}
_, _ = .WriteString(`<a href="`)
:= .URL()
:= .Label()
if .AutoLinkType == ast.AutoLinkEmail && !bytes.HasPrefix(bytes.ToLower(), []byte("mailto:")) {
_, _ = .WriteString("mailto:")
}
_, _ = .Write(util.EscapeHTML(util.URLEscape(, false)))
if .Attributes() != nil {
_ = .WriteByte('"')
RenderAttributes(, , LinkAttributeFilter)
_ = .WriteByte('>')
} else {
_, _ = .WriteString(`">`)
}
_, _ = .Write(util.EscapeHTML())
_, _ = .WriteString(`</a>`)
return ast.WalkContinue, nil
}
var CodeAttributeFilter = GlobalAttributeFilter
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if {
if .Attributes() != nil {
_, _ = .WriteString("<code")
RenderAttributes(, , CodeAttributeFilter)
_ = .WriteByte('>')
} else {
_, _ = .WriteString("<code>")
}
for := .FirstChild(); != nil; = .NextSibling() {
:= .(*ast.Text).Segment
:= .Value()
if bytes.HasSuffix(, []byte("\n")) {
.Writer.RawWrite(, [:len()-1])
if != .LastChild() {
.Writer.RawWrite(, []byte(" "))
}
} else {
.Writer.RawWrite(, )
}
}
return ast.WalkSkipChildren, nil
}
_, _ = .WriteString("</code>")
return ast.WalkContinue, nil
}
var EmphasisAttributeFilter = GlobalAttributeFilter
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
:= .(*ast.Emphasis)
:= "em"
if .Level == 2 {
= "strong"
}
if {
_ = .WriteByte('<')
_, _ = .WriteString()
if .Attributes() != nil {
RenderAttributes(, , EmphasisAttributeFilter)
}
_ = .WriteByte('>')
} else {
_, _ = .WriteString("</")
_, _ = .WriteString()
_ = .WriteByte('>')
}
return ast.WalkContinue, nil
}
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
:= .(*ast.Link)
if {
_, _ = .WriteString("<a href=\"")
if .Unsafe || !IsDangerousURL(.Destination) {
_, _ = .Write(util.EscapeHTML(util.URLEscape(.Destination, true)))
}
_ = .WriteByte('"')
if .Title != nil {
_, _ = .WriteString(` title="`)
.Writer.Write(, .Title)
_ = .WriteByte('"')
}
if .Attributes() != nil {
RenderAttributes(, , LinkAttributeFilter)
}
_ = .WriteByte('>')
} else {
_, _ = .WriteString("</a>")
}
return ast.WalkContinue, nil
}
var ImageAttributeFilter = GlobalAttributeFilter.Extend(
[]byte("align"),
[]byte("border"),
[]byte("crossorigin"),
[]byte("decoding"),
[]byte("height"),
[]byte("importance"),
[]byte("intrinsicsize"),
[]byte("ismap"),
[]byte("loading"),
[]byte("referrerpolicy"),
[]byte("sizes"),
[]byte("srcset"),
[]byte("usemap"),
[]byte("width"),
)
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if ! {
return ast.WalkContinue, nil
}
:= .(*ast.Image)
_, _ = .WriteString("<img src=\"")
if .Unsafe || !IsDangerousURL(.Destination) {
_, _ = .Write(util.EscapeHTML(util.URLEscape(.Destination, true)))
}
_, _ = .WriteString(`" alt="`)
_, _ = .Write(util.EscapeHTML(.Text()))
_ = .WriteByte('"')
if .Title != nil {
_, _ = .WriteString(` title="`)
.Writer.Write(, .Title)
_ = .WriteByte('"')
}
if .Attributes() != nil {
RenderAttributes(, , ImageAttributeFilter)
}
if .XHTML {
_, _ = .WriteString(" />")
} else {
_, _ = .WriteString(">")
}
return ast.WalkSkipChildren, nil
}
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if ! {
return ast.WalkSkipChildren, nil
}
if .Unsafe {
:= .(*ast.RawHTML)
:= .Segments.Len()
for := 0; < ; ++ {
:= .Segments.At()
_, _ = .Write(.Value())
}
return ast.WalkSkipChildren, nil
}
_, _ = .WriteString("<!-- raw HTML omitted -->")
return ast.WalkSkipChildren, nil
}
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if ! {
return ast.WalkContinue, nil
}
:= .(*ast.Text)
:= .Segment
if .IsRaw() {
.Writer.RawWrite(, .Value())
} else {
.Writer.Write(, .Value())
if .HardLineBreak() || (.SoftLineBreak() && .HardWraps) {
if .XHTML {
_, _ = .WriteString("<br />\n")
} else {
_, _ = .WriteString("<br>\n")
}
} else if .SoftLineBreak() {
_ = .WriteByte('\n')
}
}
return ast.WalkContinue, nil
}
func ( *Renderer) ( util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
if ! {
return ast.WalkContinue, nil
}
:= .(*ast.String)
if .IsCode() {
_, _ = .Write(.Value)
} else {
if .IsRaw() {
.Writer.RawWrite(, .Value)
} else {
.Writer.Write(, .Value)
}
}
return ast.WalkContinue, nil
}
var dataPrefix = []byte("data-")
func ( util.BufWriter, ast.Node, util.BytesFilter) {
for , := range .Attributes() {
if != nil && !.Contains(.Name) {
if !bytes.HasPrefix(.Name, dataPrefix) {
continue
}
}
_, _ = .WriteString(" ")
_, _ = .Write(.Name)
RawWrite(writer util.BufWriter, source []byte)
}
type defaultWriter struct {
}
func ( util.BufWriter, rune) {
if < 256 {
:= util.EscapeHTMLByte(byte())
if != nil {
_, _ = .Write()
return
}
}
_, _ = .WriteRune(util.ToValidRune())
}
func ( *defaultWriter) ( util.BufWriter, []byte) {
:= 0
:= len()
for := 0; < ; ++ {
:= util.EscapeHTMLByte([])
if != nil {
_, _ = .Write([- : ])
= 0
_, _ = .Write()
continue
}
++
}
if != 0 {
_, _ = .Write([-:])
}
}
func ( *defaultWriter) ( util.BufWriter, []byte) {
:= false
var bool
:= len()
:= 0
for := 0; < ; ++ {
:= []
if {
if util.IsPunct() {
.RawWrite(, [:-1])
=
= false
continue
}
}
if == '&' {
:=
:= + 1
if < && [] == '#' {
:= + 1
if < {
if < && == 'x' || == 'X' {
:= + 1
, = util.ReadWhile(, [2]int{, }, util.IsHexDecimal)
if && < && [] == ';' {
, := strconv.ParseUint(util.BytesToReadOnlyString([:]), 16, 32)
.RawWrite(, [:])
= + 1
escapeRune(, rune())
continue
if && < && [] == ';' {
:= util.BytesToReadOnlyString([:])
, := util.LookUpHTML5EntityByName()
if {
.RawWrite(, [:])
= + 1
.RawWrite(, .Characters)
continue
}
}
}
= - 1
}
if == '\\' {
= true
continue
}
= false
}
.RawWrite(, [:])
}
var DefaultWriter = &defaultWriter{}
var bDataImage = []byte("data:image/")
var bPng = []byte("png;")
var bGif = []byte("gif;")
var bJpeg = []byte("jpeg;")
var bWebp = []byte("webp;")
var bJs = []byte("javascript:")
var bVb = []byte("vbscript:")
var bFile = []byte("file:")
var bData = []byte("data:")
func ( []byte) bool {
if bytes.HasPrefix(, bDataImage) && len() >= 11 {
:= [11:]
if bytes.HasPrefix(, bPng) || bytes.HasPrefix(, bGif) ||
bytes.HasPrefix(, bJpeg) || bytes.HasPrefix(, bWebp) {
return false
}
return true
}
return bytes.HasPrefix(, bJs) || bytes.HasPrefix(, bVb) ||
bytes.HasPrefix(, bFile) || bytes.HasPrefix(, bData)
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |