package html

import (
	
	
	

	
	
	
)
A Config struct has configurations for the HTML based renderers.
NewConfig returns a new Config with defaults.
SetOption implements renderer.NodeRenderer.SetOption.
func ( *Config) ( renderer.OptionName,  interface{}) {
	switch  {
	case optHardWraps:
		.HardWraps = .(bool)
	case optXHTML:
		.XHTML = .(bool)
	case optUnsafe:
		.Unsafe = .(bool)
	case optTextWriter:
		.Writer = .(Writer)
	}
}
An Option interface sets options for HTML based renderers.
type Option interface {
	SetHTMLOption(*Config)
}
TextWriter is an option name used in WithWriter.
const optTextWriter renderer.OptionName = "Writer"

type withWriter struct {
	value Writer
}

func ( *withWriter) ( *renderer.Config) {
	.Options[optTextWriter] = .value
}

func ( *withWriter) ( *Config) {
	.Writer = .value
}
WithWriter is a functional option that allow you to set the given writer to the renderer.
func ( Writer) interface {
	renderer.Option
	Option
} {
	return &withWriter{}
}
HardWraps is an option name used in WithHardWraps.
WithHardWraps is a functional option that indicates whether softline breaks should be rendered as '<br>'.
func () interface {
	renderer.Option
	Option
} {
	return &withHardWraps{}
}
XHTML is an option name used in WithXHTML.
const optXHTML renderer.OptionName = "XHTML"

type withXHTML struct {
}

func ( *withXHTML) ( *renderer.Config) {
	.Options[optXHTML] = true
}

func ( *withXHTML) ( *Config) {
	.XHTML = true
}
WithXHTML is a functional option indicates that nodes should be rendered in xhtml instead of HTML5.
func () interface {
	Option
	renderer.Option
} {
	return &withXHTML{}
}
Unsafe is an option name used in WithUnsafe.
const optUnsafe renderer.OptionName = "Unsafe"

type withUnsafe struct {
}

func ( *withUnsafe) ( *renderer.Config) {
	.Options[optUnsafe] = true
}

func ( *withUnsafe) ( *Config) {
	.Unsafe = true
}
WithUnsafe is a functional option that renders dangerous contents (raw htmls and potentially dangerous links) as it is.
func () interface {
	renderer.Option
	Option
} {
	return &withUnsafe{}
}
A Renderer struct is an implementation of renderer.NodeRenderer that renders nodes as (X)HTML.
type Renderer struct {
	Config
}
NewRenderer returns a new Renderer with given options.
func ( ...Option) renderer.NodeRenderer {
	 := &Renderer{
		Config: NewConfig(),
	}

	for ,  := range  {
		.SetHTMLOption(&.Config)
	}
	return 
}
RegisterFuncs implements NodeRenderer.RegisterFuncs .
GlobalAttributeFilter defines attribute names which any elements can have.
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"),
)

nothing to do
	return ast.WalkContinue, nil
}
HeadingAttributeFilter defines attribute names which heading elements can have
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
}
BlockquoteAttributeFilter defines attribute names which blockquote elements can have
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
}
ListAttributeFilter defines attribute names which list elements can have.
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
}
ListItemAttributeFilter defines attribute names which list item elements can have.
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
}
ParagraphAttributeFilter defines attribute names which paragraph elements can have.
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
}
ThematicAttributeFilter defines attribute names which hr elements can have.
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
}
LinkAttributeFilter defines attribute names which link elements can have.
[]byte("href"),
	[]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
}
CodeAttributeFilter defines attribute names which code elements can have.
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
}
EmphasisAttributeFilter defines attribute names which emphasis elements can have.
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
}
ImageAttributeFilter defines attribute names which image elements can have.
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-")
RenderAttributes renders given node's attributes. You can specify attribute names to render by the filter. If filter is nil, RenderAttributes renders all attributes.
func ( util.BufWriter,  ast.Node,  util.BytesFilter) {
	for ,  := range .Attributes() {
		if  != nil && !.Contains(.Name) {
			if !bytes.HasPrefix(.Name, dataPrefix) {
				continue
			}
		}
		_, _ = .WriteString(" ")
		_, _ = .Write(.Name)
TODO: convert numeric values to strings
		_, _ = .Write(util.EscapeHTML(.Value.([]byte)))
		_ = .WriteByte('"')
	}
}
A Writer interface writes textual contents to a writer.
Write writes the given source to writer with resolving references and unescaping backslash escaped characters.
	Write(writer util.BufWriter, source []byte)
RawWrite writes the given source to writer without resolving references and unescaping backslash escaped characters.
	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  <  {
code point like #x22;
					if  <  &&  == 'x' ||  == 'X' {
						 :=  + 1
						,  = util.ReadWhile(, [2]int{, }, util.IsHexDecimal)
						if  &&  <  && [] == ';' {
							,  := strconv.ParseUint(util.BytesToReadOnlyString([:]), 16, 32)
							.RawWrite(, [:])
							 =  + 1
							escapeRune(, rune())
							continue
code point like #1234;
					} else if  >= '0' &&  <= '9' {
						 := 
						,  = util.ReadWhile(, [2]int{, }, util.IsNumeric)
						if  &&  <  && - < 8 && [] == ';' {
							,  := strconv.ParseUint(util.BytesToReadOnlyString([:]), 0, 32)
							.RawWrite(, [:])
							 =  + 1
							escapeRune(, rune())
							continue
						}
					}
				}
			} else {
				 := 
entity reference
				if  &&  <  && [] == ';' {
					 := util.BytesToReadOnlyString([:])
					,  := util.LookUpHTML5EntityByName()
					if  {
						.RawWrite(, [:])
						 =  + 1
						.RawWrite(, .Characters)
						continue
					}
				}
			}
			 =  - 1
		}
		if  == '\\' {
			 = true
			continue
		}
		 = false
	}
	.RawWrite(, [:])
}
DefaultWriter is a default implementation of the Writer.
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:")
IsDangerousURL returns true if the given url seems a potentially dangerous url, otherwise false.
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)