mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 18:02:26 -06:00 
			
		
		
		
	[bugfix] html escape special characters in text instead of totally removing them (#719)
* remove minify dependency * tidy up some tests * remove pre + postformat funcs * rework sanitization + formatting * update tests * add some more markdown tests
This commit is contained in:
		
					parent
					
						
							
								098dbe6ff4
							
						
					
				
			
			
				commit
				
					
						c84384e660
					
				
			
		
					 51 changed files with 129 additions and 7419 deletions
				
			
		
							
								
								
									
										137
									
								
								vendor/github.com/tdewolff/minify/v2/html/buffer.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										137
									
								
								vendor/github.com/tdewolff/minify/v2/html/buffer.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,137 +0,0 @@
 | 
			
		|||
package html
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/tdewolff/parse/v2"
 | 
			
		||||
	"github.com/tdewolff/parse/v2/html"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Token is a single token unit with an attribute value (if given) and hash of the data.
 | 
			
		||||
type Token struct {
 | 
			
		||||
	html.TokenType
 | 
			
		||||
	Hash    Hash
 | 
			
		||||
	Data    []byte
 | 
			
		||||
	Text    []byte
 | 
			
		||||
	AttrVal []byte
 | 
			
		||||
	Traits  traits
 | 
			
		||||
	Offset  int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TokenBuffer is a buffer that allows for token look-ahead.
 | 
			
		||||
type TokenBuffer struct {
 | 
			
		||||
	r *parse.Input
 | 
			
		||||
	l *html.Lexer
 | 
			
		||||
 | 
			
		||||
	buf []Token
 | 
			
		||||
	pos int
 | 
			
		||||
 | 
			
		||||
	attrBuffer []*Token
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewTokenBuffer returns a new TokenBuffer.
 | 
			
		||||
func NewTokenBuffer(r *parse.Input, l *html.Lexer) *TokenBuffer {
 | 
			
		||||
	return &TokenBuffer{
 | 
			
		||||
		r:   r,
 | 
			
		||||
		l:   l,
 | 
			
		||||
		buf: make([]Token, 0, 8),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (z *TokenBuffer) read(t *Token) {
 | 
			
		||||
	t.Offset = z.r.Offset()
 | 
			
		||||
	t.TokenType, t.Data = z.l.Next()
 | 
			
		||||
	t.Text = z.l.Text()
 | 
			
		||||
	if t.TokenType == html.AttributeToken {
 | 
			
		||||
		t.Offset += 1 + len(t.Text) + 1
 | 
			
		||||
		t.AttrVal = z.l.AttrVal()
 | 
			
		||||
		if len(t.AttrVal) > 1 && (t.AttrVal[0] == '"' || t.AttrVal[0] == '\'') {
 | 
			
		||||
			t.Offset++
 | 
			
		||||
			t.AttrVal = t.AttrVal[1 : len(t.AttrVal)-1] // quotes will be readded in attribute loop if necessary
 | 
			
		||||
		}
 | 
			
		||||
		t.Hash = ToHash(t.Text)
 | 
			
		||||
		t.Traits = attrMap[t.Hash]
 | 
			
		||||
	} else if t.TokenType == html.StartTagToken || t.TokenType == html.EndTagToken {
 | 
			
		||||
		t.AttrVal = nil
 | 
			
		||||
		t.Hash = ToHash(t.Text)
 | 
			
		||||
		t.Traits = tagMap[t.Hash] // zero if not exist
 | 
			
		||||
	} else {
 | 
			
		||||
		t.AttrVal = nil
 | 
			
		||||
		t.Hash = 0
 | 
			
		||||
		t.Traits = 0
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Peek returns the ith element and possibly does an allocation.
 | 
			
		||||
// Peeking past an error will panic.
 | 
			
		||||
func (z *TokenBuffer) Peek(pos int) *Token {
 | 
			
		||||
	pos += z.pos
 | 
			
		||||
	if pos >= len(z.buf) {
 | 
			
		||||
		if len(z.buf) > 0 && z.buf[len(z.buf)-1].TokenType == html.ErrorToken {
 | 
			
		||||
			return &z.buf[len(z.buf)-1]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c := cap(z.buf)
 | 
			
		||||
		d := len(z.buf) - z.pos
 | 
			
		||||
		p := pos - z.pos + 1 // required peek length
 | 
			
		||||
		var buf []Token
 | 
			
		||||
		if 2*p > c {
 | 
			
		||||
			buf = make([]Token, 0, 2*c+p)
 | 
			
		||||
		} else {
 | 
			
		||||
			buf = z.buf
 | 
			
		||||
		}
 | 
			
		||||
		copy(buf[:d], z.buf[z.pos:])
 | 
			
		||||
 | 
			
		||||
		buf = buf[:p]
 | 
			
		||||
		pos -= z.pos
 | 
			
		||||
		for i := d; i < p; i++ {
 | 
			
		||||
			z.read(&buf[i])
 | 
			
		||||
			if buf[i].TokenType == html.ErrorToken {
 | 
			
		||||
				buf = buf[:i+1]
 | 
			
		||||
				pos = i
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		z.pos, z.buf = 0, buf
 | 
			
		||||
	}
 | 
			
		||||
	return &z.buf[pos]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Shift returns the first element and advances position.
 | 
			
		||||
func (z *TokenBuffer) Shift() *Token {
 | 
			
		||||
	if z.pos >= len(z.buf) {
 | 
			
		||||
		t := &z.buf[:1][0]
 | 
			
		||||
		z.read(t)
 | 
			
		||||
		return t
 | 
			
		||||
	}
 | 
			
		||||
	t := &z.buf[z.pos]
 | 
			
		||||
	z.pos++
 | 
			
		||||
	return t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Attributes extracts the gives attribute hashes from a tag.
 | 
			
		||||
// It returns in the same order pointers to the requested token data or nil.
 | 
			
		||||
func (z *TokenBuffer) Attributes(hashes ...Hash) []*Token {
 | 
			
		||||
	n := 0
 | 
			
		||||
	for {
 | 
			
		||||
		if t := z.Peek(n); t.TokenType != html.AttributeToken {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		n++
 | 
			
		||||
	}
 | 
			
		||||
	if len(hashes) > cap(z.attrBuffer) {
 | 
			
		||||
		z.attrBuffer = make([]*Token, len(hashes))
 | 
			
		||||
	} else {
 | 
			
		||||
		z.attrBuffer = z.attrBuffer[:len(hashes)]
 | 
			
		||||
		for i := range z.attrBuffer {
 | 
			
		||||
			z.attrBuffer[i] = nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for i := z.pos; i < z.pos+n; i++ {
 | 
			
		||||
		attr := &z.buf[i]
 | 
			
		||||
		for j, hash := range hashes {
 | 
			
		||||
			if hash == attr.Hash {
 | 
			
		||||
				z.attrBuffer[j] = attr
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return z.attrBuffer
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										543
									
								
								vendor/github.com/tdewolff/minify/v2/html/hash.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										543
									
								
								vendor/github.com/tdewolff/minify/v2/html/hash.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,543 +0,0 @@
 | 
			
		|||
package html
 | 
			
		||||
 | 
			
		||||
// generated by hasher -type=Hash -file=hash.go; DO NOT EDIT, except for adding more constants to the list and rerun go generate
 | 
			
		||||
 | 
			
		||||
// uses github.com/tdewolff/hasher
 | 
			
		||||
//go:generate hasher -type=Hash -file=hash.go
 | 
			
		||||
 | 
			
		||||
// Hash defines perfect hashes for a predefined list of strings
 | 
			
		||||
type Hash uint32
 | 
			
		||||
 | 
			
		||||
// Unique hash definitions to be used instead of strings
 | 
			
		||||
const (
 | 
			
		||||
	A               Hash = 0x1     // a
 | 
			
		||||
	Abbr            Hash = 0x37a04 // abbr
 | 
			
		||||
	About           Hash = 0x5     // about
 | 
			
		||||
	Accept          Hash = 0x1106  // accept
 | 
			
		||||
	Accept_Charset  Hash = 0x110e  // accept-charset
 | 
			
		||||
	Action          Hash = 0x23f06 // action
 | 
			
		||||
	Address         Hash = 0x5a07  // address
 | 
			
		||||
	Align           Hash = 0x32705 // align
 | 
			
		||||
	Alink           Hash = 0x7005  // alink
 | 
			
		||||
	Allowfullscreen Hash = 0x2ad0f // allowfullscreen
 | 
			
		||||
	Amp_Boilerplate Hash = 0x610f  // amp-boilerplate
 | 
			
		||||
	Area            Hash = 0x1e304 // area
 | 
			
		||||
	Article         Hash = 0x2707  // article
 | 
			
		||||
	Aside           Hash = 0xb405  // aside
 | 
			
		||||
	Async           Hash = 0xac05  // async
 | 
			
		||||
	Audio           Hash = 0xd105  // audio
 | 
			
		||||
	Autofocus       Hash = 0xe409  // autofocus
 | 
			
		||||
	Autoplay        Hash = 0x10808 // autoplay
 | 
			
		||||
	Axis            Hash = 0x11004 // axis
 | 
			
		||||
	B               Hash = 0x101   // b
 | 
			
		||||
	Background      Hash = 0x300a  // background
 | 
			
		||||
	Base            Hash = 0x19604 // base
 | 
			
		||||
	Bb              Hash = 0x37b02 // bb
 | 
			
		||||
	Bdi             Hash = 0x7503  // bdi
 | 
			
		||||
	Bdo             Hash = 0x31f03 // bdo
 | 
			
		||||
	Bgcolor         Hash = 0x12607 // bgcolor
 | 
			
		||||
	Blockquote      Hash = 0x13e0a // blockquote
 | 
			
		||||
	Body            Hash = 0xd04   // body
 | 
			
		||||
	Br              Hash = 0x37c02 // br
 | 
			
		||||
	Button          Hash = 0x14806 // button
 | 
			
		||||
	Canvas          Hash = 0xb006  // canvas
 | 
			
		||||
	Caption         Hash = 0x21f07 // caption
 | 
			
		||||
	Charset         Hash = 0x1807  // charset
 | 
			
		||||
	Checked         Hash = 0x1b307 // checked
 | 
			
		||||
	Cite            Hash = 0xfb04  // cite
 | 
			
		||||
	Class           Hash = 0x15905 // class
 | 
			
		||||
	Classid         Hash = 0x15907 // classid
 | 
			
		||||
	Clear           Hash = 0x2b05  // clear
 | 
			
		||||
	Code            Hash = 0x19204 // code
 | 
			
		||||
	Codebase        Hash = 0x19208 // codebase
 | 
			
		||||
	Codetype        Hash = 0x1a408 // codetype
 | 
			
		||||
	Col             Hash = 0x12803 // col
 | 
			
		||||
	Colgroup        Hash = 0x1bb08 // colgroup
 | 
			
		||||
	Color           Hash = 0x12805 // color
 | 
			
		||||
	Cols            Hash = 0x1cf04 // cols
 | 
			
		||||
	Colspan         Hash = 0x1cf07 // colspan
 | 
			
		||||
	Compact         Hash = 0x1ec07 // compact
 | 
			
		||||
	Content         Hash = 0x28407 // content
 | 
			
		||||
	Controls        Hash = 0x20108 // controls
 | 
			
		||||
	Data            Hash = 0x1f04  // data
 | 
			
		||||
	Datalist        Hash = 0x1f08  // datalist
 | 
			
		||||
	Datatype        Hash = 0x4d08  // datatype
 | 
			
		||||
	Dd              Hash = 0x5b02  // dd
 | 
			
		||||
	Declare         Hash = 0xb707  // declare
 | 
			
		||||
	Default         Hash = 0x7f07  // default
 | 
			
		||||
	DefaultChecked  Hash = 0x1730e // defaultChecked
 | 
			
		||||
	DefaultMuted    Hash = 0x7f0c  // defaultMuted
 | 
			
		||||
	DefaultSelected Hash = 0x8a0f  // defaultSelected
 | 
			
		||||
	Defer           Hash = 0x9805  // defer
 | 
			
		||||
	Del             Hash = 0x10503 // del
 | 
			
		||||
	Details         Hash = 0x15f07 // details
 | 
			
		||||
	Dfn             Hash = 0x16c03 // dfn
 | 
			
		||||
	Dialog          Hash = 0xa606  // dialog
 | 
			
		||||
	Dir             Hash = 0x7603  // dir
 | 
			
		||||
	Disabled        Hash = 0x18008 // disabled
 | 
			
		||||
	Div             Hash = 0x18703 // div
 | 
			
		||||
	Dl              Hash = 0x1b902 // dl
 | 
			
		||||
	Dt              Hash = 0x23102 // dt
 | 
			
		||||
	Em              Hash = 0x4302  // em
 | 
			
		||||
	Embed           Hash = 0x4905  // embed
 | 
			
		||||
	Enabled         Hash = 0x26c07 // enabled
 | 
			
		||||
	Enctype         Hash = 0x1fa07 // enctype
 | 
			
		||||
	Face            Hash = 0x5604  // face
 | 
			
		||||
	Fieldset        Hash = 0x21408 // fieldset
 | 
			
		||||
	Figcaption      Hash = 0x21c0a // figcaption
 | 
			
		||||
	Figure          Hash = 0x22606 // figure
 | 
			
		||||
	Footer          Hash = 0xdb06  // footer
 | 
			
		||||
	For             Hash = 0x23b03 // for
 | 
			
		||||
	Form            Hash = 0x23b04 // form
 | 
			
		||||
	Formaction      Hash = 0x23b0a // formaction
 | 
			
		||||
	Formnovalidate  Hash = 0x2450e // formnovalidate
 | 
			
		||||
	Frame           Hash = 0x28c05 // frame
 | 
			
		||||
	Frameborder     Hash = 0x28c0b // frameborder
 | 
			
		||||
	H1              Hash = 0x2e002 // h1
 | 
			
		||||
	H2              Hash = 0x25302 // h2
 | 
			
		||||
	H3              Hash = 0x25502 // h3
 | 
			
		||||
	H4              Hash = 0x25702 // h4
 | 
			
		||||
	H5              Hash = 0x25902 // h5
 | 
			
		||||
	H6              Hash = 0x25b02 // h6
 | 
			
		||||
	Head            Hash = 0x2d204 // head
 | 
			
		||||
	Header          Hash = 0x2d206 // header
 | 
			
		||||
	Hgroup          Hash = 0x25d06 // hgroup
 | 
			
		||||
	Hidden          Hash = 0x26806 // hidden
 | 
			
		||||
	Hr              Hash = 0x32d02 // hr
 | 
			
		||||
	Href            Hash = 0x32d04 // href
 | 
			
		||||
	Hreflang        Hash = 0x32d08 // hreflang
 | 
			
		||||
	Html            Hash = 0x27304 // html
 | 
			
		||||
	Http_Equiv      Hash = 0x2770a // http-equiv
 | 
			
		||||
	I               Hash = 0x2401  // i
 | 
			
		||||
	Icon            Hash = 0x28304 // icon
 | 
			
		||||
	Id              Hash = 0xb602  // id
 | 
			
		||||
	Iframe          Hash = 0x28b06 // iframe
 | 
			
		||||
	Img             Hash = 0x29703 // img
 | 
			
		||||
	Inert           Hash = 0xf605  // inert
 | 
			
		||||
	Inlist          Hash = 0x29a06 // inlist
 | 
			
		||||
	Input           Hash = 0x2a405 // input
 | 
			
		||||
	Ins             Hash = 0x2a903 // ins
 | 
			
		||||
	Ismap           Hash = 0x11205 // ismap
 | 
			
		||||
	Itemscope       Hash = 0xfc09  // itemscope
 | 
			
		||||
	Kbd             Hash = 0x7403  // kbd
 | 
			
		||||
	Keygen          Hash = 0x1f606 // keygen
 | 
			
		||||
	Label           Hash = 0xbe05  // label
 | 
			
		||||
	Lang            Hash = 0x33104 // lang
 | 
			
		||||
	Language        Hash = 0x33108 // language
 | 
			
		||||
	Legend          Hash = 0x2c506 // legend
 | 
			
		||||
	Li              Hash = 0x2302  // li
 | 
			
		||||
	Link            Hash = 0x7104  // link
 | 
			
		||||
	Longdesc        Hash = 0xc208  // longdesc
 | 
			
		||||
	Main            Hash = 0xf404  // main
 | 
			
		||||
	Manifest        Hash = 0x2bc08 // manifest
 | 
			
		||||
	Map             Hash = 0xee03  // map
 | 
			
		||||
	Mark            Hash = 0x2cb04 // mark
 | 
			
		||||
	Math            Hash = 0x2cf04 // math
 | 
			
		||||
	Max             Hash = 0x2d803 // max
 | 
			
		||||
	Maxlength       Hash = 0x2d809 // maxlength
 | 
			
		||||
	Media           Hash = 0xa405  // media
 | 
			
		||||
	Menu            Hash = 0x12204 // menu
 | 
			
		||||
	Meta            Hash = 0x2e204 // meta
 | 
			
		||||
	Meter           Hash = 0x2f705 // meter
 | 
			
		||||
	Method          Hash = 0x2fc06 // method
 | 
			
		||||
	Multiple        Hash = 0x30208 // multiple
 | 
			
		||||
	Muted           Hash = 0x30a05 // muted
 | 
			
		||||
	Name            Hash = 0xa204  // name
 | 
			
		||||
	Nav             Hash = 0x32403 // nav
 | 
			
		||||
	Nohref          Hash = 0x32b06 // nohref
 | 
			
		||||
	Noresize        Hash = 0x13608 // noresize
 | 
			
		||||
	Noscript        Hash = 0x14d08 // noscript
 | 
			
		||||
	Noshade         Hash = 0x16e07 // noshade
 | 
			
		||||
	Novalidate      Hash = 0x2490a // novalidate
 | 
			
		||||
	Nowrap          Hash = 0x1d506 // nowrap
 | 
			
		||||
	Object          Hash = 0xd506  // object
 | 
			
		||||
	Ol              Hash = 0xcb02  // ol
 | 
			
		||||
	Open            Hash = 0x32104 // open
 | 
			
		||||
	Optgroup        Hash = 0x35608 // optgroup
 | 
			
		||||
	Option          Hash = 0x30f06 // option
 | 
			
		||||
	Output          Hash = 0x206   // output
 | 
			
		||||
	P               Hash = 0x501   // p
 | 
			
		||||
	Param           Hash = 0xf005  // param
 | 
			
		||||
	Pauseonexit     Hash = 0x1160b // pauseonexit
 | 
			
		||||
	Picture         Hash = 0x1c207 // picture
 | 
			
		||||
	Plaintext       Hash = 0x1da09 // plaintext
 | 
			
		||||
	Poster          Hash = 0x26206 // poster
 | 
			
		||||
	Pre             Hash = 0x35d03 // pre
 | 
			
		||||
	Prefix          Hash = 0x35d06 // prefix
 | 
			
		||||
	Profile         Hash = 0x36407 // profile
 | 
			
		||||
	Progress        Hash = 0x34208 // progress
 | 
			
		||||
	Property        Hash = 0x31508 // property
 | 
			
		||||
	Q               Hash = 0x14301 // q
 | 
			
		||||
	Rb              Hash = 0x2f02  // rb
 | 
			
		||||
	Readonly        Hash = 0x1e408 // readonly
 | 
			
		||||
	Rel             Hash = 0xbc03  // rel
 | 
			
		||||
	Required        Hash = 0x22a08 // required
 | 
			
		||||
	Resource        Hash = 0x1c708 // resource
 | 
			
		||||
	Rev             Hash = 0x7803  // rev
 | 
			
		||||
	Reversed        Hash = 0x7808  // reversed
 | 
			
		||||
	Rows            Hash = 0x9c04  // rows
 | 
			
		||||
	Rowspan         Hash = 0x9c07  // rowspan
 | 
			
		||||
	Rp              Hash = 0x6a02  // rp
 | 
			
		||||
	Rt              Hash = 0x2802  // rt
 | 
			
		||||
	Rtc             Hash = 0xf903  // rtc
 | 
			
		||||
	Ruby            Hash = 0xe004  // ruby
 | 
			
		||||
	Rules           Hash = 0x12c05 // rules
 | 
			
		||||
	S               Hash = 0x1c01  // s
 | 
			
		||||
	Samp            Hash = 0x6004  // samp
 | 
			
		||||
	Scope           Hash = 0x10005 // scope
 | 
			
		||||
	Scoped          Hash = 0x10006 // scoped
 | 
			
		||||
	Script          Hash = 0x14f06 // script
 | 
			
		||||
	Scrolling       Hash = 0xc809  // scrolling
 | 
			
		||||
	Seamless        Hash = 0x19808 // seamless
 | 
			
		||||
	Section         Hash = 0x13007 // section
 | 
			
		||||
	Select          Hash = 0x16506 // select
 | 
			
		||||
	Selected        Hash = 0x16508 // selected
 | 
			
		||||
	Shape           Hash = 0x19f05 // shape
 | 
			
		||||
	Size            Hash = 0x13a04 // size
 | 
			
		||||
	Slot            Hash = 0x20804 // slot
 | 
			
		||||
	Small           Hash = 0x2ab05 // small
 | 
			
		||||
	Sortable        Hash = 0x2ef08 // sortable
 | 
			
		||||
	Source          Hash = 0x1c906 // source
 | 
			
		||||
	Span            Hash = 0x9f04  // span
 | 
			
		||||
	Src             Hash = 0x34903 // src
 | 
			
		||||
	Srcset          Hash = 0x34906 // srcset
 | 
			
		||||
	Start           Hash = 0x2505  // start
 | 
			
		||||
	Strong          Hash = 0x29e06 // strong
 | 
			
		||||
	Style           Hash = 0x2c205 // style
 | 
			
		||||
	Sub             Hash = 0x31d03 // sub
 | 
			
		||||
	Summary         Hash = 0x33907 // summary
 | 
			
		||||
	Sup             Hash = 0x34003 // sup
 | 
			
		||||
	Svg             Hash = 0x34f03 // svg
 | 
			
		||||
	Tabindex        Hash = 0x2e408 // tabindex
 | 
			
		||||
	Table           Hash = 0x2f205 // table
 | 
			
		||||
	Target          Hash = 0x706   // target
 | 
			
		||||
	Tbody           Hash = 0xc05   // tbody
 | 
			
		||||
	Td              Hash = 0x1e02  // td
 | 
			
		||||
	Template        Hash = 0x4208  // template
 | 
			
		||||
	Text            Hash = 0x1df04 // text
 | 
			
		||||
	Textarea        Hash = 0x1df08 // textarea
 | 
			
		||||
	Tfoot           Hash = 0xda05  // tfoot
 | 
			
		||||
	Th              Hash = 0x2d102 // th
 | 
			
		||||
	Thead           Hash = 0x2d105 // thead
 | 
			
		||||
	Time            Hash = 0x12004 // time
 | 
			
		||||
	Title           Hash = 0x15405 // title
 | 
			
		||||
	Tr              Hash = 0x1f202 // tr
 | 
			
		||||
	Track           Hash = 0x1f205 // track
 | 
			
		||||
	Translate       Hash = 0x20b09 // translate
 | 
			
		||||
	Truespeed       Hash = 0x23209 // truespeed
 | 
			
		||||
	Type            Hash = 0x5104  // type
 | 
			
		||||
	Typemustmatch   Hash = 0x1a80d // typemustmatch
 | 
			
		||||
	Typeof          Hash = 0x5106  // typeof
 | 
			
		||||
	U               Hash = 0x301   // u
 | 
			
		||||
	Ul              Hash = 0x8302  // ul
 | 
			
		||||
	Undeterminate   Hash = 0x370d  // undeterminate
 | 
			
		||||
	Usemap          Hash = 0xeb06  // usemap
 | 
			
		||||
	Valign          Hash = 0x32606 // valign
 | 
			
		||||
	Value           Hash = 0x18905 // value
 | 
			
		||||
	Valuetype       Hash = 0x18909 // valuetype
 | 
			
		||||
	Var             Hash = 0x28003 // var
 | 
			
		||||
	Video           Hash = 0x35205 // video
 | 
			
		||||
	Visible         Hash = 0x36b07 // visible
 | 
			
		||||
	Vlink           Hash = 0x37205 // vlink
 | 
			
		||||
	Vocab           Hash = 0x37705 // vocab
 | 
			
		||||
	Wbr             Hash = 0x37e03 // wbr
 | 
			
		||||
	Xmlns           Hash = 0x2eb05 // xmlns
 | 
			
		||||
	Xmp             Hash = 0x36203 // xmp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// String returns the hash' name.
 | 
			
		||||
func (i Hash) String() string {
 | 
			
		||||
	start := uint32(i >> 8)
 | 
			
		||||
	n := uint32(i & 0xff)
 | 
			
		||||
	if start+n > uint32(len(_Hash_text)) {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return _Hash_text[start : start+n]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToHash returns the hash whose name is s. It returns zero if there is no
 | 
			
		||||
// such hash. It is case sensitive.
 | 
			
		||||
func ToHash(s []byte) Hash {
 | 
			
		||||
	if len(s) == 0 || len(s) > _Hash_maxLen {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	h := uint32(_Hash_hash0)
 | 
			
		||||
	for i := 0; i < len(s); i++ {
 | 
			
		||||
		h ^= uint32(s[i])
 | 
			
		||||
		h *= 16777619
 | 
			
		||||
	}
 | 
			
		||||
	if i := _Hash_table[h&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) {
 | 
			
		||||
		t := _Hash_text[i>>8 : i>>8+i&0xff]
 | 
			
		||||
		for i := 0; i < len(s); i++ {
 | 
			
		||||
			if t[i] != s[i] {
 | 
			
		||||
				goto NEXT
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return i
 | 
			
		||||
	}
 | 
			
		||||
NEXT:
 | 
			
		||||
	if i := _Hash_table[(h>>16)&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) {
 | 
			
		||||
		t := _Hash_text[i>>8 : i>>8+i&0xff]
 | 
			
		||||
		for i := 0; i < len(s); i++ {
 | 
			
		||||
			if t[i] != s[i] {
 | 
			
		||||
				return 0
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return i
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const _Hash_hash0 = 0x9acb0442
 | 
			
		||||
const _Hash_maxLen = 15
 | 
			
		||||
const _Hash_text = "aboutputargetbodyaccept-charsetdatalistarticlearbackgroundet" +
 | 
			
		||||
	"erminatemplatembedatatypeofaceaddressamp-boilerplatealinkbdi" +
 | 
			
		||||
	"reversedefaultMutedefaultSelectedeferowspanamedialogasyncanv" +
 | 
			
		||||
	"asideclarelabelongdescrollingaudiobjectfooterubyautofocusema" +
 | 
			
		||||
	"paramainertcitemscopedelautoplayaxismapauseonexitimenubgcolo" +
 | 
			
		||||
	"rulesectionoresizeblockquotebuttonoscriptitleclassidetailsel" +
 | 
			
		||||
	"ectedfnoshadefaultCheckedisabledivaluetypecodebaseamlesshape" +
 | 
			
		||||
	"codetypemustmatcheckedlcolgroupicturesourcecolspanowraplaint" +
 | 
			
		||||
	"extareadonlycompactrackeygenctypecontrolslotranslatefieldset" +
 | 
			
		||||
	"figcaptionfigurequiredtruespeedformactionformnovalidateh2h3h" +
 | 
			
		||||
	"4h5h6hgrouposterhiddenabledhtmlhttp-equivaricontentiframebor" +
 | 
			
		||||
	"derimginlistronginputinsmallowfullscreenmanifestylegendmarkm" +
 | 
			
		||||
	"atheadermaxlength1metabindexmlnsortablemetermethodmultiplemu" +
 | 
			
		||||
	"tedoptionpropertysubdopenavalignohreflanguagesummarysuprogre" +
 | 
			
		||||
	"ssrcsetsvgvideoptgrouprefixmprofilevisiblevlinkvocabbrwbr"
 | 
			
		||||
 | 
			
		||||
var _Hash_table = [1 << 9]Hash{
 | 
			
		||||
	0x0:   0x1df08, // textarea
 | 
			
		||||
	0x4:   0x32d02, // hr
 | 
			
		||||
	0x8:   0x1c207, // picture
 | 
			
		||||
	0xb:   0x18905, // value
 | 
			
		||||
	0xf:   0x2e408, // tabindex
 | 
			
		||||
	0x12:  0x15905, // class
 | 
			
		||||
	0x15:  0x37e03, // wbr
 | 
			
		||||
	0x18:  0x1a80d, // typemustmatch
 | 
			
		||||
	0x1a:  0x1b902, // dl
 | 
			
		||||
	0x1d:  0xf903,  // rtc
 | 
			
		||||
	0x1e:  0x25702, // h4
 | 
			
		||||
	0x22:  0x2ef08, // sortable
 | 
			
		||||
	0x24:  0x4208,  // template
 | 
			
		||||
	0x25:  0x28c0b, // frameborder
 | 
			
		||||
	0x28:  0x37a04, // abbr
 | 
			
		||||
	0x29:  0x28b06, // iframe
 | 
			
		||||
	0x2a:  0x610f,  // amp-boilerplate
 | 
			
		||||
	0x2c:  0x1e408, // readonly
 | 
			
		||||
	0x30:  0x23f06, // action
 | 
			
		||||
	0x33:  0x28c05, // frame
 | 
			
		||||
	0x35:  0x12c05, // rules
 | 
			
		||||
	0x36:  0x30208, // multiple
 | 
			
		||||
	0x38:  0x31f03, // bdo
 | 
			
		||||
	0x39:  0x1d506, // nowrap
 | 
			
		||||
	0x3e:  0x21408, // fieldset
 | 
			
		||||
	0x3f:  0x7503,  // bdi
 | 
			
		||||
	0x46:  0x7f0c,  // defaultMuted
 | 
			
		||||
	0x49:  0x35205, // video
 | 
			
		||||
	0x4c:  0x19808, // seamless
 | 
			
		||||
	0x4d:  0x13608, // noresize
 | 
			
		||||
	0x4f:  0xb602,  // id
 | 
			
		||||
	0x51:  0x25d06, // hgroup
 | 
			
		||||
	0x52:  0x23102, // dt
 | 
			
		||||
	0x55:  0x12805, // color
 | 
			
		||||
	0x56:  0x34003, // sup
 | 
			
		||||
	0x59:  0x370d,  // undeterminate
 | 
			
		||||
	0x5a:  0x35608, // optgroup
 | 
			
		||||
	0x5b:  0x2d206, // header
 | 
			
		||||
	0x5c:  0xb405,  // aside
 | 
			
		||||
	0x5f:  0x10005, // scope
 | 
			
		||||
	0x60:  0x101,   // b
 | 
			
		||||
	0x61:  0xcb02,  // ol
 | 
			
		||||
	0x64:  0x32b06, // nohref
 | 
			
		||||
	0x65:  0x1da09, // plaintext
 | 
			
		||||
	0x66:  0x20804, // slot
 | 
			
		||||
	0x67:  0x11004, // axis
 | 
			
		||||
	0x68:  0x12803, // col
 | 
			
		||||
	0x69:  0x32606, // valign
 | 
			
		||||
	0x6c:  0x2d105, // thead
 | 
			
		||||
	0x70:  0x34906, // srcset
 | 
			
		||||
	0x71:  0x26806, // hidden
 | 
			
		||||
	0x76:  0x1bb08, // colgroup
 | 
			
		||||
	0x78:  0x34f03, // svg
 | 
			
		||||
	0x7b:  0x2cb04, // mark
 | 
			
		||||
	0x7e:  0x33104, // lang
 | 
			
		||||
	0x81:  0x1cf04, // cols
 | 
			
		||||
	0x86:  0x5a07,  // address
 | 
			
		||||
	0x8b:  0xf404,  // main
 | 
			
		||||
	0x8c:  0x4302,  // em
 | 
			
		||||
	0x8f:  0x32d08, // hreflang
 | 
			
		||||
	0x93:  0x1b307, // checked
 | 
			
		||||
	0x94:  0x25902, // h5
 | 
			
		||||
	0x95:  0x301,   // u
 | 
			
		||||
	0x96:  0x32705, // align
 | 
			
		||||
	0x97:  0x14301, // q
 | 
			
		||||
	0x99:  0xd506,  // object
 | 
			
		||||
	0x9b:  0x28407, // content
 | 
			
		||||
	0x9d:  0xc809,  // scrolling
 | 
			
		||||
	0x9f:  0x36407, // profile
 | 
			
		||||
	0xa0:  0x34903, // src
 | 
			
		||||
	0xa1:  0xda05,  // tfoot
 | 
			
		||||
	0xa3:  0x2f705, // meter
 | 
			
		||||
	0xa4:  0x37705, // vocab
 | 
			
		||||
	0xa6:  0xd04,   // body
 | 
			
		||||
	0xa8:  0x19204, // code
 | 
			
		||||
	0xac:  0x20108, // controls
 | 
			
		||||
	0xb0:  0x2ab05, // small
 | 
			
		||||
	0xb1:  0x18008, // disabled
 | 
			
		||||
	0xb5:  0x5604,  // face
 | 
			
		||||
	0xb6:  0x501,   // p
 | 
			
		||||
	0xb9:  0x2302,  // li
 | 
			
		||||
	0xbb:  0xe409,  // autofocus
 | 
			
		||||
	0xbf:  0x27304, // html
 | 
			
		||||
	0xc2:  0x4d08,  // datatype
 | 
			
		||||
	0xc6:  0x35d06, // prefix
 | 
			
		||||
	0xcb:  0x35d03, // pre
 | 
			
		||||
	0xcc:  0x1106,  // accept
 | 
			
		||||
	0xd1:  0x23b03, // for
 | 
			
		||||
	0xd5:  0x29e06, // strong
 | 
			
		||||
	0xd6:  0x9c07,  // rowspan
 | 
			
		||||
	0xd7:  0x25502, // h3
 | 
			
		||||
	0xd8:  0x2cf04, // math
 | 
			
		||||
	0xde:  0x16e07, // noshade
 | 
			
		||||
	0xdf:  0x19f05, // shape
 | 
			
		||||
	0xe1:  0x10006, // scoped
 | 
			
		||||
	0xe3:  0x706,   // target
 | 
			
		||||
	0xe6:  0x21c0a, // figcaption
 | 
			
		||||
	0xe9:  0x1df04, // text
 | 
			
		||||
	0xea:  0x1c708, // resource
 | 
			
		||||
	0xec:  0xee03,  // map
 | 
			
		||||
	0xf0:  0x29a06, // inlist
 | 
			
		||||
	0xf1:  0x16506, // select
 | 
			
		||||
	0xf2:  0x1f606, // keygen
 | 
			
		||||
	0xf3:  0x5106,  // typeof
 | 
			
		||||
	0xf6:  0xb006,  // canvas
 | 
			
		||||
	0xf7:  0x30f06, // option
 | 
			
		||||
	0xf8:  0xbe05,  // label
 | 
			
		||||
	0xf9:  0xbc03,  // rel
 | 
			
		||||
	0xfb:  0x1f04,  // data
 | 
			
		||||
	0xfd:  0x6004,  // samp
 | 
			
		||||
	0x100: 0x110e,  // accept-charset
 | 
			
		||||
	0x101: 0xeb06,  // usemap
 | 
			
		||||
	0x103: 0x2bc08, // manifest
 | 
			
		||||
	0x109: 0xa204,  // name
 | 
			
		||||
	0x10a: 0x14806, // button
 | 
			
		||||
	0x10b: 0x2b05,  // clear
 | 
			
		||||
	0x10e: 0x33907, // summary
 | 
			
		||||
	0x10f: 0x2e204, // meta
 | 
			
		||||
	0x110: 0x33108, // language
 | 
			
		||||
	0x112: 0x300a,  // background
 | 
			
		||||
	0x113: 0x2707,  // article
 | 
			
		||||
	0x116: 0x23b0a, // formaction
 | 
			
		||||
	0x119: 0x1,     // a
 | 
			
		||||
	0x11b: 0x5,     // about
 | 
			
		||||
	0x11c: 0xfc09,  // itemscope
 | 
			
		||||
	0x11e: 0x14d08, // noscript
 | 
			
		||||
	0x11f: 0x15907, // classid
 | 
			
		||||
	0x120: 0x36203, // xmp
 | 
			
		||||
	0x121: 0x19604, // base
 | 
			
		||||
	0x123: 0x1c01,  // s
 | 
			
		||||
	0x124: 0x36b07, // visible
 | 
			
		||||
	0x126: 0x37b02, // bb
 | 
			
		||||
	0x127: 0x9c04,  // rows
 | 
			
		||||
	0x12d: 0x2450e, // formnovalidate
 | 
			
		||||
	0x131: 0x1f205, // track
 | 
			
		||||
	0x135: 0x18703, // div
 | 
			
		||||
	0x136: 0xac05,  // async
 | 
			
		||||
	0x137: 0x31508, // property
 | 
			
		||||
	0x13a: 0x16c03, // dfn
 | 
			
		||||
	0x13e: 0xf605,  // inert
 | 
			
		||||
	0x142: 0x10503, // del
 | 
			
		||||
	0x144: 0x25302, // h2
 | 
			
		||||
	0x147: 0x2c205, // style
 | 
			
		||||
	0x149: 0x29703, // img
 | 
			
		||||
	0x14a: 0xc05,   // tbody
 | 
			
		||||
	0x14b: 0x7603,  // dir
 | 
			
		||||
	0x14c: 0x2eb05, // xmlns
 | 
			
		||||
	0x14e: 0x1f08,  // datalist
 | 
			
		||||
	0x14f: 0x32d04, // href
 | 
			
		||||
	0x150: 0x1f202, // tr
 | 
			
		||||
	0x151: 0x13e0a, // blockquote
 | 
			
		||||
	0x152: 0x18909, // valuetype
 | 
			
		||||
	0x155: 0xdb06,  // footer
 | 
			
		||||
	0x157: 0x14f06, // script
 | 
			
		||||
	0x158: 0x1cf07, // colspan
 | 
			
		||||
	0x15d: 0x1730e, // defaultChecked
 | 
			
		||||
	0x15f: 0x2490a, // novalidate
 | 
			
		||||
	0x164: 0x1a408, // codetype
 | 
			
		||||
	0x165: 0x2c506, // legend
 | 
			
		||||
	0x16b: 0x1160b, // pauseonexit
 | 
			
		||||
	0x16c: 0x21f07, // caption
 | 
			
		||||
	0x16f: 0x26c07, // enabled
 | 
			
		||||
	0x173: 0x26206, // poster
 | 
			
		||||
	0x175: 0x30a05, // muted
 | 
			
		||||
	0x176: 0x11205, // ismap
 | 
			
		||||
	0x178: 0x2a903, // ins
 | 
			
		||||
	0x17a: 0xe004,  // ruby
 | 
			
		||||
	0x17b: 0x37c02, // br
 | 
			
		||||
	0x17c: 0x8a0f,  // defaultSelected
 | 
			
		||||
	0x17d: 0x7403,  // kbd
 | 
			
		||||
	0x17f: 0x1c906, // source
 | 
			
		||||
	0x182: 0x9f04,  // span
 | 
			
		||||
	0x184: 0x2d803, // max
 | 
			
		||||
	0x18a: 0x5b02,  // dd
 | 
			
		||||
	0x18b: 0x13a04, // size
 | 
			
		||||
	0x18c: 0xa405,  // media
 | 
			
		||||
	0x18d: 0x19208, // codebase
 | 
			
		||||
	0x18f: 0x4905,  // embed
 | 
			
		||||
	0x192: 0x5104,  // type
 | 
			
		||||
	0x193: 0xf005,  // param
 | 
			
		||||
	0x194: 0x25b02, // h6
 | 
			
		||||
	0x197: 0x28304, // icon
 | 
			
		||||
	0x198: 0x12607, // bgcolor
 | 
			
		||||
	0x199: 0x2ad0f, // allowfullscreen
 | 
			
		||||
	0x19a: 0x12004, // time
 | 
			
		||||
	0x19b: 0x7803,  // rev
 | 
			
		||||
	0x19d: 0x34208, // progress
 | 
			
		||||
	0x19e: 0x22606, // figure
 | 
			
		||||
	0x1a0: 0x6a02,  // rp
 | 
			
		||||
	0x1a2: 0xa606,  // dialog
 | 
			
		||||
	0x1a4: 0x2802,  // rt
 | 
			
		||||
	0x1a7: 0x1e304, // area
 | 
			
		||||
	0x1a8: 0x7808,  // reversed
 | 
			
		||||
	0x1aa: 0x32104, // open
 | 
			
		||||
	0x1ac: 0x2d204, // head
 | 
			
		||||
	0x1ad: 0x7005,  // alink
 | 
			
		||||
	0x1af: 0x28003, // var
 | 
			
		||||
	0x1b0: 0x15f07, // details
 | 
			
		||||
	0x1b1: 0x2401,  // i
 | 
			
		||||
	0x1b3: 0x1e02,  // td
 | 
			
		||||
	0x1b4: 0xb707,  // declare
 | 
			
		||||
	0x1b5: 0x8302,  // ul
 | 
			
		||||
	0x1ba: 0x2fc06, // method
 | 
			
		||||
	0x1bd: 0x13007, // section
 | 
			
		||||
	0x1be: 0x22a08, // required
 | 
			
		||||
	0x1c2: 0x9805,  // defer
 | 
			
		||||
	0x1c3: 0x37205, // vlink
 | 
			
		||||
	0x1c4: 0x15405, // title
 | 
			
		||||
	0x1c5: 0x2770a, // http-equiv
 | 
			
		||||
	0x1c6: 0x1fa07, // enctype
 | 
			
		||||
	0x1c7: 0x1ec07, // compact
 | 
			
		||||
	0x1c8: 0x2d809, // maxlength
 | 
			
		||||
	0x1c9: 0x16508, // selected
 | 
			
		||||
	0x1cc: 0xd105,  // audio
 | 
			
		||||
	0x1cd: 0xc208,  // longdesc
 | 
			
		||||
	0x1d1: 0xfb04,  // cite
 | 
			
		||||
	0x1da: 0x2505,  // start
 | 
			
		||||
	0x1de: 0x2d102, // th
 | 
			
		||||
	0x1df: 0x10808, // autoplay
 | 
			
		||||
	0x1e2: 0x7104,  // link
 | 
			
		||||
	0x1e3: 0x206,   // output
 | 
			
		||||
	0x1e5: 0x12204, // menu
 | 
			
		||||
	0x1e6: 0x2a405, // input
 | 
			
		||||
	0x1eb: 0x32403, // nav
 | 
			
		||||
	0x1ec: 0x31d03, // sub
 | 
			
		||||
	0x1ee: 0x1807,  // charset
 | 
			
		||||
	0x1ef: 0x7f07,  // default
 | 
			
		||||
	0x1f3: 0x2f205, // table
 | 
			
		||||
	0x1f4: 0x23b04, // form
 | 
			
		||||
	0x1f5: 0x23209, // truespeed
 | 
			
		||||
	0x1f6: 0x2f02,  // rb
 | 
			
		||||
	0x1fb: 0x20b09, // translate
 | 
			
		||||
	0x1fd: 0x2e002, // h1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										511
									
								
								vendor/github.com/tdewolff/minify/v2/html/html.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										511
									
								
								vendor/github.com/tdewolff/minify/v2/html/html.go
									
										
									
										generated
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,511 +0,0 @@
 | 
			
		|||
// Package html minifies HTML5 following the specifications at http://www.w3.org/TR/html5/syntax.html.
 | 
			
		||||
package html
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/tdewolff/minify/v2"
 | 
			
		||||
	"github.com/tdewolff/parse/v2"
 | 
			
		||||
	"github.com/tdewolff/parse/v2/buffer"
 | 
			
		||||
	"github.com/tdewolff/parse/v2/html"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	gtBytes         = []byte(">")
 | 
			
		||||
	isBytes         = []byte("=")
 | 
			
		||||
	spaceBytes      = []byte(" ")
 | 
			
		||||
	doctypeBytes    = []byte("<!doctype html>")
 | 
			
		||||
	jsMimeBytes     = []byte("application/javascript")
 | 
			
		||||
	cssMimeBytes    = []byte("text/css")
 | 
			
		||||
	htmlMimeBytes   = []byte("text/html")
 | 
			
		||||
	svgMimeBytes    = []byte("image/svg+xml")
 | 
			
		||||
	formMimeBytes   = []byte("application/x-www-form-urlencoded")
 | 
			
		||||
	mathMimeBytes   = []byte("application/mathml+xml")
 | 
			
		||||
	dataSchemeBytes = []byte("data:")
 | 
			
		||||
	jsSchemeBytes   = []byte("javascript:")
 | 
			
		||||
	httpBytes       = []byte("http")
 | 
			
		||||
	radioBytes      = []byte("radio")
 | 
			
		||||
	onBytes         = []byte("on")
 | 
			
		||||
	textBytes       = []byte("text")
 | 
			
		||||
	noneBytes       = []byte("none")
 | 
			
		||||
	submitBytes     = []byte("submit")
 | 
			
		||||
	allBytes        = []byte("all")
 | 
			
		||||
	rectBytes       = []byte("rect")
 | 
			
		||||
	dataBytes       = []byte("data")
 | 
			
		||||
	getBytes        = []byte("get")
 | 
			
		||||
	autoBytes       = []byte("auto")
 | 
			
		||||
	oneBytes        = []byte("one")
 | 
			
		||||
	inlineParams    = map[string]string{"inline": "1"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// DefaultMinifier is the default minifier.
 | 
			
		||||
var DefaultMinifier = &Minifier{}
 | 
			
		||||
 | 
			
		||||
// Minifier is an HTML minifier.
 | 
			
		||||
type Minifier struct {
 | 
			
		||||
	KeepComments            bool
 | 
			
		||||
	KeepConditionalComments bool
 | 
			
		||||
	KeepDefaultAttrVals     bool
 | 
			
		||||
	KeepDocumentTags        bool
 | 
			
		||||
	KeepEndTags             bool
 | 
			
		||||
	KeepQuotes              bool
 | 
			
		||||
	KeepWhitespace          bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Minify minifies HTML data, it reads from r and writes to w.
 | 
			
		||||
func Minify(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error {
 | 
			
		||||
	return DefaultMinifier.Minify(m, w, r, params)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Minify minifies HTML data, it reads from r and writes to w.
 | 
			
		||||
func (o *Minifier) Minify(m *minify.M, w io.Writer, r io.Reader, _ map[string]string) error {
 | 
			
		||||
	var rawTagHash Hash
 | 
			
		||||
	var rawTagMediatype []byte
 | 
			
		||||
 | 
			
		||||
	omitSpace := true // if true the next leading space is omitted
 | 
			
		||||
	inPre := false
 | 
			
		||||
 | 
			
		||||
	attrMinifyBuffer := buffer.NewWriter(make([]byte, 0, 64))
 | 
			
		||||
	attrByteBuffer := make([]byte, 0, 64)
 | 
			
		||||
 | 
			
		||||
	z := parse.NewInput(r)
 | 
			
		||||
	defer z.Restore()
 | 
			
		||||
 | 
			
		||||
	l := html.NewLexer(z)
 | 
			
		||||
	tb := NewTokenBuffer(z, l)
 | 
			
		||||
	for {
 | 
			
		||||
		t := *tb.Shift()
 | 
			
		||||
		switch t.TokenType {
 | 
			
		||||
		case html.ErrorToken:
 | 
			
		||||
			if _, err := w.Write(nil); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if l.Err() == io.EOF {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			return l.Err()
 | 
			
		||||
		case html.DoctypeToken:
 | 
			
		||||
			w.Write(doctypeBytes)
 | 
			
		||||
		case html.CommentToken:
 | 
			
		||||
			if o.KeepComments {
 | 
			
		||||
				w.Write(t.Data)
 | 
			
		||||
			} else if o.KeepConditionalComments && 6 < len(t.Text) && (bytes.HasPrefix(t.Text, []byte("[if ")) || bytes.HasSuffix(t.Text, []byte("[endif]")) || bytes.HasSuffix(t.Text, []byte("[endif]--"))) {
 | 
			
		||||
				// [if ...] is always 7 or more characters, [endif] is only encountered for downlevel-revealed
 | 
			
		||||
				// see https://msdn.microsoft.com/en-us/library/ms537512(v=vs.85).aspx#syntax
 | 
			
		||||
				if bytes.HasPrefix(t.Data, []byte("<!--[if ")) && bytes.HasSuffix(t.Data, []byte("<![endif]-->")) { // downlevel-hidden
 | 
			
		||||
					begin := bytes.IndexByte(t.Data, '>') + 1
 | 
			
		||||
					end := len(t.Data) - len("<![endif]-->")
 | 
			
		||||
					w.Write(t.Data[:begin])
 | 
			
		||||
					if err := o.Minify(m, w, buffer.NewReader(t.Data[begin:end]), nil); err != nil {
 | 
			
		||||
						return minify.UpdateErrorPosition(err, z, t.Offset)
 | 
			
		||||
					}
 | 
			
		||||
					w.Write(t.Data[end:])
 | 
			
		||||
				} else {
 | 
			
		||||
					w.Write(t.Data) // downlevel-revealed or short downlevel-hidden
 | 
			
		||||
				}
 | 
			
		||||
			} else if 1 < len(t.Text) && t.Text[0] == '#' {
 | 
			
		||||
				// SSI tags
 | 
			
		||||
				w.Write(t.Data)
 | 
			
		||||
			}
 | 
			
		||||
		case html.SvgToken:
 | 
			
		||||
			if err := m.MinifyMimetype(svgMimeBytes, w, buffer.NewReader(t.Data), nil); err != nil {
 | 
			
		||||
				if err != minify.ErrNotExist {
 | 
			
		||||
					return minify.UpdateErrorPosition(err, z, t.Offset)
 | 
			
		||||
				}
 | 
			
		||||
				w.Write(t.Data)
 | 
			
		||||
			}
 | 
			
		||||
		case html.MathToken:
 | 
			
		||||
			if err := m.MinifyMimetype(mathMimeBytes, w, buffer.NewReader(t.Data), nil); err != nil {
 | 
			
		||||
				if err != minify.ErrNotExist {
 | 
			
		||||
					return minify.UpdateErrorPosition(err, z, t.Offset)
 | 
			
		||||
				}
 | 
			
		||||
				w.Write(t.Data)
 | 
			
		||||
			}
 | 
			
		||||
		case html.TextToken:
 | 
			
		||||
			// CSS and JS minifiers for inline code
 | 
			
		||||
			if rawTagHash != 0 {
 | 
			
		||||
				if rawTagHash == Style || rawTagHash == Script || rawTagHash == Iframe {
 | 
			
		||||
					var mimetype []byte
 | 
			
		||||
					var params map[string]string
 | 
			
		||||
					if rawTagHash == Iframe {
 | 
			
		||||
						mimetype = htmlMimeBytes
 | 
			
		||||
					} else if len(rawTagMediatype) > 0 {
 | 
			
		||||
						mimetype, params = parse.Mediatype(rawTagMediatype)
 | 
			
		||||
					} else if rawTagHash == Script {
 | 
			
		||||
						mimetype = jsMimeBytes
 | 
			
		||||
					} else if rawTagHash == Style {
 | 
			
		||||
						mimetype = cssMimeBytes
 | 
			
		||||
					}
 | 
			
		||||
					if err := m.MinifyMimetype(mimetype, w, buffer.NewReader(t.Data), params); err != nil {
 | 
			
		||||
						if err != minify.ErrNotExist {
 | 
			
		||||
							return minify.UpdateErrorPosition(err, z, t.Offset)
 | 
			
		||||
						}
 | 
			
		||||
						w.Write(t.Data)
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					w.Write(t.Data)
 | 
			
		||||
				}
 | 
			
		||||
			} else if inPre {
 | 
			
		||||
				w.Write(t.Data)
 | 
			
		||||
			} else {
 | 
			
		||||
				t.Data = parse.ReplaceMultipleWhitespaceAndEntities(t.Data, EntitiesMap, TextRevEntitiesMap)
 | 
			
		||||
 | 
			
		||||
				// whitespace removal; trim left
 | 
			
		||||
				if omitSpace && parse.IsWhitespace(t.Data[0]) {
 | 
			
		||||
					t.Data = t.Data[1:]
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// whitespace removal; trim right
 | 
			
		||||
				omitSpace = false
 | 
			
		||||
				if len(t.Data) == 0 {
 | 
			
		||||
					omitSpace = true
 | 
			
		||||
				} else if parse.IsWhitespace(t.Data[len(t.Data)-1]) {
 | 
			
		||||
					omitSpace = true
 | 
			
		||||
					i := 0
 | 
			
		||||
					for {
 | 
			
		||||
						next := tb.Peek(i)
 | 
			
		||||
						// trim if EOF, text token with leading whitespace or block token
 | 
			
		||||
						if next.TokenType == html.ErrorToken {
 | 
			
		||||
							t.Data = t.Data[:len(t.Data)-1]
 | 
			
		||||
							omitSpace = false
 | 
			
		||||
							break
 | 
			
		||||
						} else if next.TokenType == html.TextToken {
 | 
			
		||||
							// this only happens when a comment, doctype or phrasing end tag (only for !o.KeepWhitespace) was in between
 | 
			
		||||
							// remove if the text token starts with a whitespace
 | 
			
		||||
							if len(next.Data) > 0 && parse.IsWhitespace(next.Data[0]) {
 | 
			
		||||
								t.Data = t.Data[:len(t.Data)-1]
 | 
			
		||||
								omitSpace = false
 | 
			
		||||
							}
 | 
			
		||||
							break
 | 
			
		||||
						} else if next.TokenType == html.StartTagToken || next.TokenType == html.EndTagToken {
 | 
			
		||||
							if o.KeepWhitespace {
 | 
			
		||||
								break
 | 
			
		||||
							}
 | 
			
		||||
							// remove when followed up by a block tag
 | 
			
		||||
							if next.Traits&nonPhrasingTag != 0 {
 | 
			
		||||
								t.Data = t.Data[:len(t.Data)-1]
 | 
			
		||||
								omitSpace = false
 | 
			
		||||
								break
 | 
			
		||||
							} else if next.TokenType == html.StartTagToken {
 | 
			
		||||
								break
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						i++
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				w.Write(t.Data)
 | 
			
		||||
			}
 | 
			
		||||
		case html.StartTagToken, html.EndTagToken:
 | 
			
		||||
			rawTagHash = 0
 | 
			
		||||
			hasAttributes := false
 | 
			
		||||
			if t.TokenType == html.StartTagToken {
 | 
			
		||||
				if next := tb.Peek(0); next.TokenType == html.AttributeToken {
 | 
			
		||||
					hasAttributes = true
 | 
			
		||||
				}
 | 
			
		||||
				if t.Traits&rawTag != 0 {
 | 
			
		||||
					// ignore empty script and style tags
 | 
			
		||||
					if !hasAttributes && (t.Hash == Script || t.Hash == Style) {
 | 
			
		||||
						if next := tb.Peek(1); next.TokenType == html.EndTagToken {
 | 
			
		||||
							tb.Shift()
 | 
			
		||||
							tb.Shift()
 | 
			
		||||
							break
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					rawTagHash = t.Hash
 | 
			
		||||
					rawTagMediatype = nil
 | 
			
		||||
 | 
			
		||||
					// do not minify content of <style amp-boilerplate>
 | 
			
		||||
					if hasAttributes && t.Hash == Style {
 | 
			
		||||
						if attrs := tb.Attributes(Amp_Boilerplate); attrs[0] != nil {
 | 
			
		||||
							rawTagHash = 0
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else if t.Hash == Template {
 | 
			
		||||
				omitSpace = true // EndTagToken
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if t.Hash == Pre {
 | 
			
		||||
				inPre = t.TokenType == html.StartTagToken
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// remove superfluous tags, except for html, head and body tags when KeepDocumentTags is set
 | 
			
		||||
			if !hasAttributes && (!o.KeepDocumentTags && (t.Hash == Html || t.Hash == Head || t.Hash == Body) || t.Hash == Colgroup) {
 | 
			
		||||
				break
 | 
			
		||||
			} else if t.TokenType == html.EndTagToken {
 | 
			
		||||
				omitEndTag := false
 | 
			
		||||
				if !o.KeepEndTags {
 | 
			
		||||
					if t.Hash == Thead || t.Hash == Tbody || t.Hash == Tfoot || t.Hash == Tr || t.Hash == Th ||
 | 
			
		||||
						t.Hash == Td || t.Hash == Option || t.Hash == Dd || t.Hash == Dt || t.Hash == Li ||
 | 
			
		||||
						t.Hash == Rb || t.Hash == Rt || t.Hash == Rtc || t.Hash == Rp {
 | 
			
		||||
						omitEndTag = true // omit end tags
 | 
			
		||||
					} else if t.Hash == P {
 | 
			
		||||
						i := 0
 | 
			
		||||
						for {
 | 
			
		||||
							next := tb.Peek(i)
 | 
			
		||||
							i++
 | 
			
		||||
							// continue if text token is empty or whitespace
 | 
			
		||||
							if next.TokenType == html.TextToken && parse.IsAllWhitespace(next.Data) {
 | 
			
		||||
								continue
 | 
			
		||||
							}
 | 
			
		||||
							if next.TokenType == html.ErrorToken || next.TokenType == html.EndTagToken && next.Traits&keepPTag == 0 || next.TokenType == html.StartTagToken && next.Traits&omitPTag != 0 {
 | 
			
		||||
								omitEndTag = true // omit p end tag
 | 
			
		||||
							}
 | 
			
		||||
							break
 | 
			
		||||
						}
 | 
			
		||||
					} else if t.Hash == Optgroup {
 | 
			
		||||
						i := 0
 | 
			
		||||
						for {
 | 
			
		||||
							next := tb.Peek(i)
 | 
			
		||||
							i++
 | 
			
		||||
							// continue if text token
 | 
			
		||||
							if next.TokenType == html.TextToken {
 | 
			
		||||
								continue
 | 
			
		||||
							}
 | 
			
		||||
							if next.TokenType == html.ErrorToken || next.Hash != Option {
 | 
			
		||||
								omitEndTag = true // omit optgroup end tag
 | 
			
		||||
							}
 | 
			
		||||
							break
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if t.Traits&nonPhrasingTag != 0 {
 | 
			
		||||
					omitSpace = true // omit spaces after block elements
 | 
			
		||||
				} else if o.KeepWhitespace || t.Traits&objectTag != 0 {
 | 
			
		||||
					omitSpace = false
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if !omitEndTag {
 | 
			
		||||
					if len(t.Data) > 3+len(t.Text) {
 | 
			
		||||
						t.Data[2+len(t.Text)] = '>'
 | 
			
		||||
						t.Data = t.Data[:3+len(t.Text)]
 | 
			
		||||
					}
 | 
			
		||||
					w.Write(t.Data)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// skip text in select and optgroup tags
 | 
			
		||||
				if t.Hash == Option || t.Hash == Optgroup {
 | 
			
		||||
					if next := tb.Peek(0); next.TokenType == html.TextToken {
 | 
			
		||||
						tb.Shift()
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if o.KeepWhitespace || t.Traits&objectTag != 0 {
 | 
			
		||||
				omitSpace = false
 | 
			
		||||
			} else if t.Traits&nonPhrasingTag != 0 {
 | 
			
		||||
				omitSpace = true // omit spaces after block elements
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			w.Write(t.Data)
 | 
			
		||||
 | 
			
		||||
			if hasAttributes {
 | 
			
		||||
				if t.Hash == Meta {
 | 
			
		||||
					attrs := tb.Attributes(Content, Http_Equiv, Charset, Name)
 | 
			
		||||
					if content := attrs[0]; content != nil {
 | 
			
		||||
						if httpEquiv := attrs[1]; httpEquiv != nil {
 | 
			
		||||
							httpEquiv.AttrVal = parse.TrimWhitespace(httpEquiv.AttrVal)
 | 
			
		||||
							if charset := attrs[2]; charset == nil && parse.EqualFold(httpEquiv.AttrVal, []byte("content-type")) {
 | 
			
		||||
								content.AttrVal = minify.Mediatype(content.AttrVal)
 | 
			
		||||
								if bytes.Equal(content.AttrVal, []byte("text/html;charset=utf-8")) {
 | 
			
		||||
									httpEquiv.Text = nil
 | 
			
		||||
									content.Text = []byte("charset")
 | 
			
		||||
									content.Hash = Charset
 | 
			
		||||
									content.AttrVal = []byte("utf-8")
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						if name := attrs[3]; name != nil {
 | 
			
		||||
							name.AttrVal = parse.TrimWhitespace(name.AttrVal)
 | 
			
		||||
							if parse.EqualFold(name.AttrVal, []byte("keywords")) {
 | 
			
		||||
								content.AttrVal = bytes.ReplaceAll(content.AttrVal, []byte(", "), []byte(","))
 | 
			
		||||
							} else if parse.EqualFold(name.AttrVal, []byte("viewport")) {
 | 
			
		||||
								content.AttrVal = bytes.ReplaceAll(content.AttrVal, []byte(" "), []byte(""))
 | 
			
		||||
								for i := 0; i < len(content.AttrVal); i++ {
 | 
			
		||||
									if content.AttrVal[i] == '=' && i+2 < len(content.AttrVal) {
 | 
			
		||||
										i++
 | 
			
		||||
										if n := parse.Number(content.AttrVal[i:]); n > 0 {
 | 
			
		||||
											minNum := minify.Number(content.AttrVal[i:i+n], -1)
 | 
			
		||||
											if len(minNum) < n {
 | 
			
		||||
												copy(content.AttrVal[i:i+len(minNum)], minNum)
 | 
			
		||||
												copy(content.AttrVal[i+len(minNum):], content.AttrVal[i+n:])
 | 
			
		||||
												content.AttrVal = content.AttrVal[:len(content.AttrVal)+len(minNum)-n]
 | 
			
		||||
											}
 | 
			
		||||
											i += len(minNum)
 | 
			
		||||
										}
 | 
			
		||||
										i-- // mitigate for-loop increase
 | 
			
		||||
									}
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				} else if t.Hash == Script {
 | 
			
		||||
					attrs := tb.Attributes(Src, Charset)
 | 
			
		||||
					if attrs[0] != nil && attrs[1] != nil {
 | 
			
		||||
						attrs[1].Text = nil
 | 
			
		||||
					}
 | 
			
		||||
				} else if t.Hash == Input {
 | 
			
		||||
					attrs := tb.Attributes(Type, Value)
 | 
			
		||||
					if t, value := attrs[0], attrs[1]; t != nil && value != nil {
 | 
			
		||||
						isRadio := parse.EqualFold(t.AttrVal, radioBytes)
 | 
			
		||||
						if !isRadio && len(value.AttrVal) == 0 {
 | 
			
		||||
							value.Text = nil
 | 
			
		||||
						} else if isRadio && parse.EqualFold(value.AttrVal, onBytes) {
 | 
			
		||||
							value.Text = nil
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				} else if t.Hash == A {
 | 
			
		||||
					attrs := tb.Attributes(Id, Name)
 | 
			
		||||
					if id, name := attrs[0], attrs[1]; id != nil && name != nil {
 | 
			
		||||
						if bytes.Equal(id.AttrVal, name.AttrVal) {
 | 
			
		||||
							name.Text = nil
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// write attributes
 | 
			
		||||
				for {
 | 
			
		||||
					attr := *tb.Shift()
 | 
			
		||||
					if attr.TokenType != html.AttributeToken {
 | 
			
		||||
						break
 | 
			
		||||
					} else if attr.Text == nil {
 | 
			
		||||
						continue // removed attribute
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					val := attr.AttrVal
 | 
			
		||||
					if attr.Traits&trimAttr != 0 {
 | 
			
		||||
						val = parse.ReplaceMultipleWhitespaceAndEntities(val, EntitiesMap, nil)
 | 
			
		||||
						val = parse.TrimWhitespace(val)
 | 
			
		||||
					} else {
 | 
			
		||||
						val = parse.ReplaceEntities(val, EntitiesMap, nil)
 | 
			
		||||
					}
 | 
			
		||||
					if t.Traits != 0 {
 | 
			
		||||
						if len(val) == 0 && (attr.Hash == Class ||
 | 
			
		||||
							attr.Hash == Dir ||
 | 
			
		||||
							attr.Hash == Id ||
 | 
			
		||||
							attr.Hash == Name ||
 | 
			
		||||
							attr.Hash == Action && t.Hash == Form) {
 | 
			
		||||
							continue // omit empty attribute values
 | 
			
		||||
						}
 | 
			
		||||
						if attr.Traits&caselessAttr != 0 {
 | 
			
		||||
							val = parse.ToLower(val)
 | 
			
		||||
							if attr.Hash == Enctype || attr.Hash == Codetype || attr.Hash == Accept || attr.Hash == Type && (t.Hash == A || t.Hash == Link || t.Hash == Embed || t.Hash == Object || t.Hash == Source || t.Hash == Script || t.Hash == Style) {
 | 
			
		||||
								val = minify.Mediatype(val)
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						if rawTagHash != 0 && attr.Hash == Type {
 | 
			
		||||
							rawTagMediatype = parse.Copy(val)
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						// default attribute values can be omitted
 | 
			
		||||
						if !o.KeepDefaultAttrVals && (attr.Hash == Type && (t.Hash == Script && jsMimetypes[string(val)] ||
 | 
			
		||||
							t.Hash == Style && bytes.Equal(val, cssMimeBytes) ||
 | 
			
		||||
							t.Hash == Link && bytes.Equal(val, cssMimeBytes) ||
 | 
			
		||||
							t.Hash == Input && bytes.Equal(val, textBytes) ||
 | 
			
		||||
							t.Hash == Button && bytes.Equal(val, submitBytes)) ||
 | 
			
		||||
							attr.Hash == Language && t.Hash == Script ||
 | 
			
		||||
							attr.Hash == Method && bytes.Equal(val, getBytes) ||
 | 
			
		||||
							attr.Hash == Enctype && bytes.Equal(val, formMimeBytes) ||
 | 
			
		||||
							attr.Hash == Colspan && bytes.Equal(val, oneBytes) ||
 | 
			
		||||
							attr.Hash == Rowspan && bytes.Equal(val, oneBytes) ||
 | 
			
		||||
							attr.Hash == Shape && bytes.Equal(val, rectBytes) ||
 | 
			
		||||
							attr.Hash == Span && bytes.Equal(val, oneBytes) ||
 | 
			
		||||
							attr.Hash == Clear && bytes.Equal(val, noneBytes) ||
 | 
			
		||||
							attr.Hash == Frameborder && bytes.Equal(val, oneBytes) ||
 | 
			
		||||
							attr.Hash == Scrolling && bytes.Equal(val, autoBytes) ||
 | 
			
		||||
							attr.Hash == Valuetype && bytes.Equal(val, dataBytes) ||
 | 
			
		||||
							attr.Hash == Media && t.Hash == Style && bytes.Equal(val, allBytes)) {
 | 
			
		||||
							continue
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						if attr.Hash == Style {
 | 
			
		||||
							// CSS minifier for attribute inline code
 | 
			
		||||
							val = parse.TrimWhitespace(val)
 | 
			
		||||
							attrMinifyBuffer.Reset()
 | 
			
		||||
							if err := m.MinifyMimetype(cssMimeBytes, attrMinifyBuffer, buffer.NewReader(val), inlineParams); err == nil {
 | 
			
		||||
								val = attrMinifyBuffer.Bytes()
 | 
			
		||||
							} else if err != minify.ErrNotExist {
 | 
			
		||||
								return minify.UpdateErrorPosition(err, z, attr.Offset)
 | 
			
		||||
							}
 | 
			
		||||
							if len(val) == 0 {
 | 
			
		||||
								continue
 | 
			
		||||
							}
 | 
			
		||||
						} else if len(attr.Text) > 2 && attr.Text[0] == 'o' && attr.Text[1] == 'n' {
 | 
			
		||||
							// JS minifier for attribute inline code
 | 
			
		||||
							val = parse.TrimWhitespace(val)
 | 
			
		||||
							if len(val) >= 11 && parse.EqualFold(val[:11], jsSchemeBytes) {
 | 
			
		||||
								val = val[11:]
 | 
			
		||||
							}
 | 
			
		||||
							attrMinifyBuffer.Reset()
 | 
			
		||||
							if err := m.MinifyMimetype(jsMimeBytes, attrMinifyBuffer, buffer.NewReader(val), nil); err == nil {
 | 
			
		||||
								val = attrMinifyBuffer.Bytes()
 | 
			
		||||
							} else if err != minify.ErrNotExist {
 | 
			
		||||
								return minify.UpdateErrorPosition(err, z, attr.Offset)
 | 
			
		||||
							}
 | 
			
		||||
							if len(val) == 0 {
 | 
			
		||||
								continue
 | 
			
		||||
							}
 | 
			
		||||
						} else if attr.Traits&urlAttr != 0 { // anchors are already handled
 | 
			
		||||
							val = parse.TrimWhitespace(val)
 | 
			
		||||
							if 5 < len(val) {
 | 
			
		||||
								if parse.EqualFold(val[:4], httpBytes) {
 | 
			
		||||
									if val[4] == ':' {
 | 
			
		||||
										if m.URL != nil && m.URL.Scheme == "http" {
 | 
			
		||||
											val = val[5:]
 | 
			
		||||
										} else {
 | 
			
		||||
											parse.ToLower(val[:4])
 | 
			
		||||
										}
 | 
			
		||||
									} else if (val[4] == 's' || val[4] == 'S') && val[5] == ':' {
 | 
			
		||||
										if m.URL != nil && m.URL.Scheme == "https" {
 | 
			
		||||
											val = val[6:]
 | 
			
		||||
										} else {
 | 
			
		||||
											parse.ToLower(val[:5])
 | 
			
		||||
										}
 | 
			
		||||
									}
 | 
			
		||||
								} else if parse.EqualFold(val[:5], dataSchemeBytes) {
 | 
			
		||||
									val = minify.DataURI(m, val)
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					w.Write(spaceBytes)
 | 
			
		||||
					w.Write(attr.Text)
 | 
			
		||||
					if len(val) > 0 && attr.Traits&booleanAttr == 0 {
 | 
			
		||||
						w.Write(isBytes)
 | 
			
		||||
 | 
			
		||||
						// use double quotes for RDFa attributes
 | 
			
		||||
						isXML := attr.Hash == Vocab || attr.Hash == Typeof || attr.Hash == Property || attr.Hash == Resource || attr.Hash == Prefix || attr.Hash == Content || attr.Hash == About || attr.Hash == Rev || attr.Hash == Datatype || attr.Hash == Inlist
 | 
			
		||||
 | 
			
		||||
						// no quotes if possible, else prefer single or double depending on which occurs more often in value
 | 
			
		||||
						val = html.EscapeAttrVal(&attrByteBuffer, attr.AttrVal, val, o.KeepQuotes || isXML)
 | 
			
		||||
						w.Write(val)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				_ = tb.Shift() // StartTagClose
 | 
			
		||||
			}
 | 
			
		||||
			w.Write(gtBytes)
 | 
			
		||||
 | 
			
		||||
			// skip text in select and optgroup tags
 | 
			
		||||
			if t.Hash == Select || t.Hash == Optgroup {
 | 
			
		||||
				if next := tb.Peek(0); next.TokenType == html.TextToken {
 | 
			
		||||
					tb.Shift()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// keep space after phrasing tags (<i>, <span>, ...) FontAwesome etc.
 | 
			
		||||
			if t.TokenType == html.StartTagToken && t.Traits&nonPhrasingTag == 0 {
 | 
			
		||||
				if next := tb.Peek(0); next.Hash == t.Hash && next.TokenType == html.EndTagToken {
 | 
			
		||||
					omitSpace = false
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1346
									
								
								vendor/github.com/tdewolff/minify/v2/html/table.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1346
									
								
								vendor/github.com/tdewolff/minify/v2/html/table.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue