Skip to content

Commit

Permalink
always lower template literals containing "</script>"
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed May 28, 2021
1 parent 5653093 commit 58ac420
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 7 deletions.
8 changes: 4 additions & 4 deletions CHANGELOG.md
Expand Up @@ -32,11 +32,12 @@

* Avoid generating the character sequence `</script>` ([#1322](https://github.com/evanw/esbuild/issues/1322))

If the output of esbuild is inlined into a `<script>...</script>` tag inside an HTML file, the character sequence `</script>` inside the JavaScript code will accidentally cause the script tag to be terminated early. There are at least three such cases where this can happen:
If the output of esbuild is inlined into a `<script>...</script>` tag inside an HTML file, the character sequence `</script>` inside the JavaScript code will accidentally cause the script tag to be terminated early. There are at least four such cases where this can happen:

```js
console.log('</script>')
console.log(1</script>/.exec(x).length)
console.log(String.raw`</script>`)
// @license </script>
```

Expand All @@ -45,11 +46,10 @@
```js
console.log('<\/script>');
console.log(1< /script>/.exec(x).length);
// @license <∕script>
console.log(String.raw(__template(["<\/script>"], ["<\/script>"])));
// @license <\/script>
```

The `@license` comment uses a different slash character. I'm not sure how to handle that one since it's meant for humans but that seemed like the least intrusive method. I expect this case to not ever come up in practice anyway.

## 0.12.4

* Reorder name preservation before TypeScript decorator evaluation ([#1316](https://github.com/evanw/esbuild/issues/1316))
Expand Down
19 changes: 18 additions & 1 deletion internal/js_parser/js_parser.go
Expand Up @@ -10724,8 +10724,25 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
expr = p.mangleTemplate(expr.Loc, e)
}

shouldLowerTemplateLiteral := p.options.unsupportedJSFeatures.Has(compat.TemplateLiteral)

// Lower tagged template literals that include "</script>"
// since we won't be able to escape it without lowering it
if !shouldLowerTemplateLiteral && e.TagOrNil.Data != nil {
if strings.Contains(e.HeadRaw, "</script>") {
shouldLowerTemplateLiteral = true
} else {
for _, part := range e.Parts {
if strings.Contains(part.TailRaw, "</script>") {
shouldLowerTemplateLiteral = true
break
}
}
}
}

// Convert template literals to older syntax if this is still a template literal
if p.options.unsupportedJSFeatures.Has(compat.TemplateLiteral) {
if shouldLowerTemplateLiteral {
if e, ok := expr.Data.(*js_ast.ETemplate); ok {
return p.lowerTemplateLiteral(expr.Loc, e), exprOut{}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/js_printer/js_printer.go
Expand Up @@ -2710,7 +2710,7 @@ func (p *printer) printIf(s *js_ast.SIf) {

func (p *printer) printIndentedComment(text string) {
// Avoid generating a comment containing the character sequence "</script>"
text = strings.ReplaceAll(text, "</script>", "<\u2215script>")
text = strings.ReplaceAll(text, "</script>", "<\\/script>")

if strings.HasPrefix(text, "/*") {
// Re-indent multi-line comments
Expand Down
4 changes: 3 additions & 1 deletion internal/js_printer/js_printer_test.go
Expand Up @@ -914,7 +914,9 @@ func TestAvoidSlashScript(t *testing.T) {
expectPrinted(t, "x = `${y}</script>`", "x = `${y}<\\/script>`;\n")
expectPrintedMinify(t, "x = 1 < /script>/.exec(y).length", "x=1< /script>/.exec(y).length;")
expectPrintedMinify(t, "x = 1 << /script>/.exec(y).length", "x=1<< /script>/.exec(y).length;")
expectPrinted(t, "//! </script>", "//! <\u2215script>\n")
expectPrinted(t, "//! </script>", "//! <\\/script>\n")
expectPrinted(t, "String.raw`</script>`",
"String.raw(__template([\"<\\/script>\"], [\"<\\/script>\"]));\nimport {\n __template\n} from \"<runtime>\";\n")

// Negative cases
expectPrinted(t, "x = '</'", "x = \"</\";\n")
Expand Down

0 comments on commit 58ac420

Please sign in to comment.