hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

context.go (8585B)

    1 // Copyright 2011 The Go Authors. All rights reserved.
    2 // Use of this source code is governed by a BSD-style
    3 // license that can be found in the LICENSE file.
    4 
    5 package template
    6 
    7 import (
    8 	"fmt"
    9 
   10 	"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
   11 )
   12 
   13 // context describes the state an HTML parser must be in when it reaches the
   14 // portion of HTML produced by evaluating a particular template node.
   15 //
   16 // The zero value of type context is the start context for a template that
   17 // produces an HTML fragment as defined at
   18 // https://www.w3.org/TR/html5/syntax.html#the-end
   19 // where the context element is null.
   20 type context struct {
   21 	state   state
   22 	delim   delim
   23 	urlPart urlPart
   24 	jsCtx   jsCtx
   25 	attr    attr
   26 	element element
   27 	n       parse.Node // for range break/continue
   28 	err     *Error
   29 }
   30 
   31 func (c context) String() string {
   32 	var err error
   33 	if c.err != nil {
   34 		err = c.err
   35 	}
   36 	return fmt.Sprintf("{%v %v %v %v %v %v %v}", c.state, c.delim, c.urlPart, c.jsCtx, c.attr, c.element, err)
   37 }
   38 
   39 // eq reports whether two contexts are equal.
   40 func (c context) eq(d context) bool {
   41 	return c.state == d.state &&
   42 		c.delim == d.delim &&
   43 		c.urlPart == d.urlPart &&
   44 		c.jsCtx == d.jsCtx &&
   45 		c.attr == d.attr &&
   46 		c.element == d.element &&
   47 		c.err == d.err
   48 }
   49 
   50 // mangle produces an identifier that includes a suffix that distinguishes it
   51 // from template names mangled with different contexts.
   52 func (c context) mangle(templateName string) string {
   53 	// The mangled name for the default context is the input templateName.
   54 	if c.state == stateText {
   55 		return templateName
   56 	}
   57 	s := templateName + "$htmltemplate_" + c.state.String()
   58 	if c.delim != delimNone {
   59 		s += "_" + c.delim.String()
   60 	}
   61 	if c.urlPart != urlPartNone {
   62 		s += "_" + c.urlPart.String()
   63 	}
   64 	if c.jsCtx != jsCtxRegexp {
   65 		s += "_" + c.jsCtx.String()
   66 	}
   67 	if c.attr != attrNone {
   68 		s += "_" + c.attr.String()
   69 	}
   70 	if c.element != elementNone {
   71 		s += "_" + c.element.String()
   72 	}
   73 	return s
   74 }
   75 
   76 // state describes a high-level HTML parser state.
   77 //
   78 // It bounds the top of the element stack, and by extension the HTML insertion
   79 // mode, but also contains state that does not correspond to anything in the
   80 // HTML5 parsing algorithm because a single token production in the HTML
   81 // grammar may contain embedded actions in a template. For instance, the quoted
   82 // HTML attribute produced by
   83 //     <div title="Hello {{.World}}">
   84 // is a single token in HTML's grammar but in a template spans several nodes.
   85 type state uint8
   86 
   87 //go:generate stringer -type state
   88 
   89 const (
   90 	// stateText is parsed character data. An HTML parser is in
   91 	// this state when its parse position is outside an HTML tag,
   92 	// directive, comment, and special element body.
   93 	stateText state = iota
   94 	// stateTag occurs before an HTML attribute or the end of a tag.
   95 	stateTag
   96 	// stateAttrName occurs inside an attribute name.
   97 	// It occurs between the ^'s in ` ^name^ = value`.
   98 	stateAttrName
   99 	// stateAfterName occurs after an attr name has ended but before any
  100 	// equals sign. It occurs between the ^'s in ` name^ ^= value`.
  101 	stateAfterName
  102 	// stateBeforeValue occurs after the equals sign but before the value.
  103 	// It occurs between the ^'s in ` name =^ ^value`.
  104 	stateBeforeValue
  105 	// stateHTMLCmt occurs inside an <!-- HTML comment -->.
  106 	stateHTMLCmt
  107 	// stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
  108 	// as described at https://www.w3.org/TR/html5/syntax.html#elements-0
  109 	stateRCDATA
  110 	// stateAttr occurs inside an HTML attribute whose content is text.
  111 	stateAttr
  112 	// stateURL occurs inside an HTML attribute whose content is a URL.
  113 	stateURL
  114 	// stateSrcset occurs inside an HTML srcset attribute.
  115 	stateSrcset
  116 	// stateJS occurs inside an event handler or script element.
  117 	stateJS
  118 	// stateJSDqStr occurs inside a JavaScript double quoted string.
  119 	stateJSDqStr
  120 	// stateJSSqStr occurs inside a JavaScript single quoted string.
  121 	stateJSSqStr
  122 	// stateJSRegexp occurs inside a JavaScript regexp literal.
  123 	stateJSRegexp
  124 	// stateJSBlockCmt occurs inside a JavaScript /* block comment */.
  125 	stateJSBlockCmt
  126 	// stateJSLineCmt occurs inside a JavaScript // line comment.
  127 	stateJSLineCmt
  128 	// stateCSS occurs inside a <style> element or style attribute.
  129 	stateCSS
  130 	// stateCSSDqStr occurs inside a CSS double quoted string.
  131 	stateCSSDqStr
  132 	// stateCSSSqStr occurs inside a CSS single quoted string.
  133 	stateCSSSqStr
  134 	// stateCSSDqURL occurs inside a CSS double quoted url("...").
  135 	stateCSSDqURL
  136 	// stateCSSSqURL occurs inside a CSS single quoted url('...').
  137 	stateCSSSqURL
  138 	// stateCSSURL occurs inside a CSS unquoted url(...).
  139 	stateCSSURL
  140 	// stateCSSBlockCmt occurs inside a CSS /* block comment */.
  141 	stateCSSBlockCmt
  142 	// stateCSSLineCmt occurs inside a CSS // line comment.
  143 	stateCSSLineCmt
  144 	// stateError is an infectious error state outside any valid
  145 	// HTML/CSS/JS construct.
  146 	stateError
  147 	// stateDead marks unreachable code after a {{break}} or {{continue}}.
  148 	stateDead
  149 )
  150 
  151 // isComment is true for any state that contains content meant for template
  152 // authors & maintainers, not for end-users or machines.
  153 func isComment(s state) bool {
  154 	switch s {
  155 	case stateHTMLCmt, stateJSBlockCmt, stateJSLineCmt, stateCSSBlockCmt, stateCSSLineCmt:
  156 		return true
  157 	}
  158 	return false
  159 }
  160 
  161 // isInTag return whether s occurs solely inside an HTML tag.
  162 func isInTag(s state) bool {
  163 	switch s {
  164 	case stateTag, stateAttrName, stateAfterName, stateBeforeValue, stateAttr:
  165 		return true
  166 	}
  167 	return false
  168 }
  169 
  170 // delim is the delimiter that will end the current HTML attribute.
  171 type delim uint8
  172 
  173 //go:generate stringer -type delim
  174 
  175 const (
  176 	// delimNone occurs outside any attribute.
  177 	delimNone delim = iota
  178 	// delimDoubleQuote occurs when a double quote (") closes the attribute.
  179 	delimDoubleQuote
  180 	// delimSingleQuote occurs when a single quote (') closes the attribute.
  181 	delimSingleQuote
  182 	// delimSpaceOrTagEnd occurs when a space or right angle bracket (>)
  183 	// closes the attribute.
  184 	delimSpaceOrTagEnd
  185 )
  186 
  187 // urlPart identifies a part in an RFC 3986 hierarchical URL to allow different
  188 // encoding strategies.
  189 type urlPart uint8
  190 
  191 //go:generate stringer -type urlPart
  192 
  193 const (
  194 	// urlPartNone occurs when not in a URL, or possibly at the start:
  195 	// ^ in "^http://auth/path?k=v#frag".
  196 	urlPartNone urlPart = iota
  197 	// urlPartPreQuery occurs in the scheme, authority, or path; between the
  198 	// ^s in "h^ttp://auth/path^?k=v#frag".
  199 	urlPartPreQuery
  200 	// urlPartQueryOrFrag occurs in the query portion between the ^s in
  201 	// "http://auth/path?^k=v#frag^".
  202 	urlPartQueryOrFrag
  203 	// urlPartUnknown occurs due to joining of contexts both before and
  204 	// after the query separator.
  205 	urlPartUnknown
  206 )
  207 
  208 // jsCtx determines whether a '/' starts a regular expression literal or a
  209 // division operator.
  210 type jsCtx uint8
  211 
  212 //go:generate stringer -type jsCtx
  213 
  214 const (
  215 	// jsCtxRegexp occurs where a '/' would start a regexp literal.
  216 	jsCtxRegexp jsCtx = iota
  217 	// jsCtxDivOp occurs where a '/' would start a division operator.
  218 	jsCtxDivOp
  219 	// jsCtxUnknown occurs where a '/' is ambiguous due to context joining.
  220 	jsCtxUnknown
  221 )
  222 
  223 // element identifies the HTML element when inside a start tag or special body.
  224 // Certain HTML element (for example <script> and <style>) have bodies that are
  225 // treated differently from stateText so the element type is necessary to
  226 // transition into the correct context at the end of a tag and to identify the
  227 // end delimiter for the body.
  228 type element uint8
  229 
  230 //go:generate stringer -type element
  231 
  232 const (
  233 	// elementNone occurs outside a special tag or special element body.
  234 	elementNone element = iota
  235 	// elementScript corresponds to the raw text <script> element
  236 	// with JS MIME type or no type attribute.
  237 	elementScript
  238 	// elementStyle corresponds to the raw text <style> element.
  239 	elementStyle
  240 	// elementTextarea corresponds to the RCDATA <textarea> element.
  241 	elementTextarea
  242 	// elementTitle corresponds to the RCDATA <title> element.
  243 	elementTitle
  244 )
  245 
  246 //go:generate stringer -type attr
  247 
  248 // attr identifies the current HTML attribute when inside the attribute,
  249 // that is, starting from stateAttrName until stateTag/stateText (exclusive).
  250 type attr uint8
  251 
  252 const (
  253 	// attrNone corresponds to a normal attribute or no attribute.
  254 	attrNone attr = iota
  255 	// attrScript corresponds to an event handler attribute.
  256 	attrScript
  257 	// attrScriptType corresponds to the type attribute in script HTML element
  258 	attrScriptType
  259 	// attrStyle corresponds to the style attribute whose value is CSS.
  260 	attrStyle
  261 	// attrURL corresponds to an attribute whose value is a URL.
  262 	attrURL
  263 	// attrSrcset corresponds to a srcset attribute.
  264 	attrSrcset
  265 )