aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/tdewolff/minify/html/buffer.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tdewolff/minify/html/buffer.go')
-rw-r--r--vendor/github.com/tdewolff/minify/html/buffer.go131
1 files changed, 131 insertions, 0 deletions
diff --git a/vendor/github.com/tdewolff/minify/html/buffer.go b/vendor/github.com/tdewolff/minify/html/buffer.go
new file mode 100644
index 0000000..8486bcb
--- /dev/null
+++ b/vendor/github.com/tdewolff/minify/html/buffer.go
@@ -0,0 +1,131 @@
+package html // import "github.com/tdewolff/minify/html"
+
+import (
+ "github.com/tdewolff/parse"
+ "github.com/tdewolff/parse/html"
+)
+
+// Token is a single token unit with an attribute value (if given) and hash of the data.
+type Token struct {
+ html.TokenType
+ Hash html.Hash
+ Data []byte
+ Text []byte
+ AttrVal []byte
+ Traits traits
+}
+
+// TokenBuffer is a buffer that allows for token look-ahead.
+type TokenBuffer struct {
+ l *html.Lexer
+
+ buf []Token
+ pos int
+
+ attrBuffer []*Token
+}
+
+// NewTokenBuffer returns a new TokenBuffer.
+func NewTokenBuffer(l *html.Lexer) *TokenBuffer {
+ return &TokenBuffer{
+ l: l,
+ buf: make([]Token, 0, 8),
+ }
+}
+
+func (z *TokenBuffer) read(t *Token) {
+ t.TokenType, t.Data = z.l.Next()
+ t.Text = z.l.Text()
+ if t.TokenType == html.AttributeToken {
+ t.AttrVal = z.l.AttrVal()
+ if len(t.AttrVal) > 1 && (t.AttrVal[0] == '"' || t.AttrVal[0] == '\'') {
+ t.AttrVal = parse.TrimWhitespace(t.AttrVal[1 : len(t.AttrVal)-1]) // quotes will be readded in attribute loop if necessary
+ }
+ t.Hash = html.ToHash(t.Text)
+ t.Traits = attrMap[t.Hash]
+ } else if t.TokenType == html.StartTagToken || t.TokenType == html.EndTagToken {
+ t.AttrVal = nil
+ t.Hash = html.ToHash(t.Text)
+ t.Traits = tagMap[t.Hash]
+ } 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 ...html.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
+}