Copyright 2011 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package template

import (
	
	
	
	
	
	
)
nextJSCtx returns the context that determines whether a slash after the given run of tokens starts a regular expression instead of a division operator: / or /=. This assumes that the token run does not include any string tokens, comment tokens, regular expression literal tokens, or division operators. This fails on some valid but nonsensical JavaScript programs like "x = ++/foo/i" which is quite different than "x++/foo/i", but is not known to fail on any known useful programs. It is based on the draft JavaScript 2.0 lexical grammar and requires one token of lookbehind: https://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html
func ( []byte,  jsCtx) jsCtx {
	 = bytes.TrimRight(, "\t\n\f\r \u2028\u2029")
	if len() == 0 {
		return 
	}
All cases below are in the single-byte UTF-8 group.
	switch ,  := [len()-1], len();  {
++ and -- are not regexp preceders, but + and - are whether they are used as infix or prefix operators.
Count the number of adjacent dashes or pluses.
		for  > 0 && [-1] ==  {
			--
		}
Reached for trailing minus signs since "---" is the same as "-- -".
			return jsCtxRegexp
		}
		return jsCtxDivOp
Handle "42."
		if  != 1 && '0' <= [-2] && [-2] <= '9' {
			return jsCtxDivOp
		}
Suffixes for all punctuators from section 7.7 of the language spec that only end binary operators not handled above.
	case ',', '<', '>', '=', '*', '%', '&', '|', '^', '?':
Suffixes for all punctuators from section 7.7 of the language spec that are prefix operators not handled above.
	case '!', '~':
Matches all the punctuators from section 7.7 of the language spec that are open brackets not handled above.
	case '(', '[':
Matches all the punctuators from section 7.7 of the language spec that precede expression starts.
	case ':', ';', '{':
CAVEAT: the close punctuators ('}', ']', ')') precede div ops and are handled in the default except for '}' which can precede a division op as in ({ valueOf: function () { return 42 } } / 2 which is valid, but, in practice, developers don't divide object literals, so our heuristic works well for code like function () { ... } /foo/.test(x) && sideEffect(); The ')' punctuator can precede a regular expression as in if (b) /foo/.test(x) && ... but this is much less likely than (a + b) / c
	case '}':
		return jsCtxRegexp
Look for an IdentifierName and see if it is a keyword that can precede a regular expression.
		 := 
		for  > 0 && isJSIdentPart(rune([-1])) {
			--
		}
		if regexpPrecederKeywords[string([:])] {
			return jsCtxRegexp
		}
Otherwise is a punctuator not listed above, or a string which precedes a div op, or an identifier which precedes a div op.
	return jsCtxDivOp
}
regexpPrecederKeywords is a set of reserved JS keywords that can precede a regular expression in JS source.
var regexpPrecederKeywords = map[string]bool{
	"break":      true,
	"case":       true,
	"continue":   true,
	"delete":     true,
	"do":         true,
	"else":       true,
	"finally":    true,
	"in":         true,
	"instanceof": true,
	"return":     true,
	"throw":      true,
	"try":        true,
	"typeof":     true,
	"void":       true,
}

var jsonMarshalType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
indirectToJSONMarshaler returns the value, after dereferencing as many times as necessary to reach the base type (or nil) or an implementation of json.Marshal.
text/template now supports passing untyped nil as a func call argument, so we must support it. Otherwise we'd panic below, as one cannot call the Type or Interface methods on an invalid reflect.Value. See golang.org/issue/18716.
	if  == nil {
		return nil
	}

	 := reflect.ValueOf()
	for !.Type().Implements(jsonMarshalType) && .Kind() == reflect.Ptr && !.IsNil() {
		 = .Elem()
	}
	return .Interface()
}
jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has neither side-effects nor free variables outside (NaN, Infinity).
func ( ...interface{}) string {
	var  interface{}
	if len() == 1 {
		 = indirectToJSONMarshaler([0])
		switch t := .(type) {
		case JS:
			return string()
TODO: normalize quotes.
			return `"` + string() + `"`
Do not treat as a Stringer.
		case fmt.Stringer:
			 = .String()
		}
	} else {
		for ,  := range  {
			[] = indirectToJSONMarshaler()
		}
		 = fmt.Sprint(...)
TODO: detect cycles before calling Marshal which loops infinitely on cyclic data. This may be an unacceptable DoS risk.
	,  := json.Marshal()
Put a space before comment so that if it is flush against a division operator it is not turned into a line comment: x/{{y}} turning into x/ error marshaling y: second line of error message null
		return fmt.Sprintf(" /* %s */null ", strings.ReplaceAll(.Error(), "*/", "* /"))
	}
TODO: maybe post-process output to prevent it from containing "<!--", "-->", "<![CDATA[", "]]>", or "</script" in case custom marshalers produce output containing those. Note: Do not use \x escaping to save bytes because it is not JSON compatible and this escaper supports ld+json content-type.
In, `x=y/{{.}}*z` a json.Marshaler that produces "" should not cause the output `x=yz`.
		return " null "
	}
	,  := utf8.DecodeRune()
	,  := utf8.DecodeLastRune()
Prevent IdentifierNames and NumericLiterals from running into keywords: in, instanceof, typeof, void
	 := isJSIdentPart() || isJSIdentPart()
	if  {
		.WriteByte(' ')
	}
Make sure that json.Marshal escapes codepoints U+2028 & U+2029 so it falls within the subset of JSON which is valid JS.
	for  := 0;  < len(); {
		,  := utf8.DecodeRune([:])
		 := ""
		if  == 0x2028 {
			 = `\u2028`
		} else if  == 0x2029 {
			 = `\u2029`
		}
		if  != "" {
			.Write([:])
			.WriteString()
			 =  + 
		}
		 += 
	}
	if .Len() != 0 {
		.Write([:])
		if  {
			.WriteByte(' ')
		}
		return .String()
	}
	return string()
}
jsStrEscaper produces a string that can be included between quotes in JavaScript source, in JavaScript embedded in an HTML5 <script> element, or in an HTML5 event handler attribute such as onclick.
func ( ...interface{}) string {
	,  := stringify(...)
	if  == contentTypeJSStr {
		return replace(, jsStrNormReplacementTable)
	}
	return replace(, jsStrReplacementTable)
}
jsRegexpEscaper behaves like jsStrEscaper but escapes regular expression specials so the result is treated literally when included in a regular expression literal. /foo{{.X}}bar/ matches the string "foo" followed by the literal text of {{.X}} followed by the string "bar".
func ( ...interface{}) string {
	,  := stringify(...)
	 = replace(, jsRegexpReplacementTable)
/{{.X}}/ should not produce a line comment when .X == "".
		return "(?:)"
	}
	return 
}
replace replaces each rune r of s with replacementTable[r], provided that r < len(replacementTable). If replacementTable[r] is the empty string then no replacement is made. It also replaces runes U+2028 and U+2029 with the raw strings `\u2028` and `\u2029`.
func ( string,  []string) string {
	var  strings.Builder
	, ,  := rune(0), 0, 0
See comment in htmlEscaper.
		,  = utf8.DecodeRuneInString([:])
		var  string
		switch {
		case int() < len(lowUnicodeReplacementTable):
			 = lowUnicodeReplacementTable[]
		case int() < len() && [] != "":
			 = []
		case  == '\u2028':
			 = `\u2028`
		case  == '\u2029':
			 = `\u2029`
		default:
			continue
		}
		if  == 0 {
			.Grow(len())
		}
		.WriteString([:])
		.WriteString()
		 =  + 
	}
	if  == 0 {
		return 
	}
	.WriteString([:])
	return .String()
}

var lowUnicodeReplacementTable = []string{
	0: `\u0000`, 1: `\u0001`, 2: `\u0002`, 3: `\u0003`, 4: `\u0004`, 5: `\u0005`, 6: `\u0006`,
	'\a': `\u0007`,
	'\b': `\u0008`,
	'\t': `\t`,
	'\n': `\n`,
	'\v': `\u000b`, // "\v" == "v" on IE 6.
	'\f': `\f`,
	'\r': `\r`,
	0xe:  `\u000e`, 0xf: `\u000f`, 0x10: `\u0010`, 0x11: `\u0011`, 0x12: `\u0012`, 0x13: `\u0013`,
	0x14: `\u0014`, 0x15: `\u0015`, 0x16: `\u0016`, 0x17: `\u0017`, 0x18: `\u0018`, 0x19: `\u0019`,
	0x1a: `\u001a`, 0x1b: `\u001b`, 0x1c: `\u001c`, 0x1d: `\u001d`, 0x1e: `\u001e`, 0x1f: `\u001f`,
}

var jsStrReplacementTable = []string{
	0:    `\u0000`,
	'\t': `\t`,
	'\n': `\n`,
	'\v': `\u000b`, // "\v" == "v" on IE 6.
	'\f': `\f`,
Encode HTML specials as hex so the output can be embedded in HTML attributes without further encoding.
	'"':  `\u0022`,
	'&':  `\u0026`,
	'\'': `\u0027`,
	'+':  `\u002b`,
	'/':  `\/`,
	'<':  `\u003c`,
	'>':  `\u003e`,
	'\\': `\\`,
}
jsStrNormReplacementTable is like jsStrReplacementTable but does not overencode existing escapes since this table has no entry for `\`.
var jsStrNormReplacementTable = []string{
	0:    `\u0000`,
	'\t': `\t`,
	'\n': `\n`,
	'\v': `\u000b`, // "\v" == "v" on IE 6.
	'\f': `\f`,
Encode HTML specials as hex so the output can be embedded in HTML attributes without further encoding.
	'"':  `\u0022`,
	'&':  `\u0026`,
	'\'': `\u0027`,
	'+':  `\u002b`,
	'/':  `\/`,
	'<':  `\u003c`,
	'>':  `\u003e`,
}
var jsRegexpReplacementTable = []string{
	0:    `\u0000`,
	'\t': `\t`,
	'\n': `\n`,
	'\v': `\u000b`, // "\v" == "v" on IE 6.
	'\f': `\f`,
Encode HTML specials as hex so the output can be embedded in HTML attributes without further encoding.
	'"':  `\u0022`,
	'$':  `\$`,
	'&':  `\u0026`,
	'\'': `\u0027`,
	'(':  `\(`,
	')':  `\)`,
	'*':  `\*`,
	'+':  `\u002b`,
	'-':  `\-`,
	'.':  `\.`,
	'/':  `\/`,
	'<':  `\u003c`,
	'>':  `\u003e`,
	'?':  `\?`,
	'[':  `\[`,
	'\\': `\\`,
	']':  `\]`,
	'^':  `\^`,
	'{':  `\{`,
	'|':  `\|`,
	'}':  `\}`,
}
isJSIdentPart reports whether the given rune is a JS identifier part. It does not handle all the non-Latin letters, joiners, and combining marks, but it does handle every codepoint that can occur in a numeric literal or a keyword.
func ( rune) bool {
	switch {
	case  == '$':
		return true
	case '0' <=  &&  <= '9':
		return true
	case 'A' <=  &&  <= 'Z':
		return true
	case  == '_':
		return true
	case 'a' <=  &&  <= 'z':
		return true
	}
	return false
}
isJSType reports whether the given MIME type should be considered JavaScript. It is used to determine whether a script tag with a type attribute is a javascript container.
per https://www.w3.org/TR/html5/scripting-1.html#attr-script-type https://tools.ietf.org/html/rfc7231#section-3.1.1 https://tools.ietf.org/html/rfc4329#section-3 https://www.ietf.org/rfc/rfc4627.txt discard parameters
	if  := strings.Index(, ";");  >= 0 {
		 = [:]
	}
	 = strings.ToLower()
	 = strings.TrimSpace()
	switch  {
	case
		"application/ecmascript",
		"application/javascript",
		"application/json",
		"application/ld+json",
		"application/x-ecmascript",
		"application/x-javascript",
		"module",
		"text/ecmascript",
		"text/javascript",
		"text/javascript1.0",
		"text/javascript1.1",
		"text/javascript1.2",
		"text/javascript1.3",
		"text/javascript1.4",
		"text/javascript1.5",
		"text/jscript",
		"text/livescript",
		"text/x-ecmascript",
		"text/x-javascript":
		return true
	default:
		return false
	}