...

Source file src/pkg/html/template/context.go

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

View as plain text