Skip to content

Commit 3dd6c57

Browse files
committed
fix #1976: parse "super()" with "--mangle-props=."
1 parent 4cc9406 commit 3dd6c57

File tree

4 files changed

+70
-1
lines changed

4 files changed

+70
-1
lines changed

CHANGELOG.md

+19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
* Avoid a syntax error due to `--mangle-props=.` and `super()` ([#1976](https://github.com/evanw/esbuild/issues/1976))
6+
7+
This release fixes an issue where passing `--mangle-props=.` (i.e. telling esbuild to mangle every single property) caused a syntax error with code like this:
8+
9+
```js
10+
class Foo {}
11+
class Bar extends Foo {
12+
constructor() {
13+
super();
14+
}
15+
}
16+
```
17+
18+
The problem was that `constructor` was being renamed to another method, which then made it no longer a constructor, which meant that `super()` was now a syntax error. I have added a workaround that avoids renaming any property named `constructor` so that esbuild doesn't generate a syntax error here.
19+
20+
Despite this fix, I highly recommend not using `--mangle-props=.` because your code will almost certainly be broken. You will have to manually add every single property that you don't want mangled to `--reserve-props=` which is an excessive maintenance burden (e.g. reserve `parse` to use `JSON.parse`). Instead I recommend using a common pattern for all properties you intend to be mangled that is unlikely to appear in the APIs you use such as "ends in an underscore." This is an opt-in approach instead of an opt-out approach. It also makes it obvious when reading the code which properties will be mangled and which ones won't be.
21+
322
## 0.14.16
423

524
* Support property name mangling with some TypeScript syntax features

internal/bundler/bundler_default_test.go

+25
Original file line numberDiff line numberDiff line change
@@ -5826,3 +5826,28 @@ func TestManglePropsLoweredClassFields(t *testing.T) {
58265826
},
58275827
})
58285828
}
5829+
5830+
// This tests for a case where "constructor" was being mangled, which made the
5831+
// method become a non-constructor, and then "super()" caused a parse error.
5832+
// The fix was to prevent the property "constructor" from being mangled.
5833+
// See: https://github.com/evanw/esbuild/issues/1976
5834+
func TestManglePropsSuperCall(t *testing.T) {
5835+
loader_suite.expectBundled(t, bundled{
5836+
files: map[string]string{
5837+
"/entry.js": `
5838+
class Foo {}
5839+
class Bar extends Foo {
5840+
constructor() {
5841+
super();
5842+
}
5843+
}
5844+
`,
5845+
},
5846+
entryPaths: []string{"/entry.js"},
5847+
options: config.Options{
5848+
Mode: config.ModePassThrough,
5849+
AbsOutputFile: "/out.js",
5850+
MangleProps: regexp.MustCompile("."),
5851+
},
5852+
})
5853+
}

internal/bundler/snapshots/snapshots_loader.txt

+11
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,17 @@ TestManglePropsShorthand
691691
---------- /out.js ----------
692692
export let yyyyy = ({ y }) => ({ y });
693693

694+
================================================================================
695+
TestManglePropsSuperCall
696+
---------- /out.js ----------
697+
class Foo {
698+
}
699+
class Bar extends Foo {
700+
constructor() {
701+
super();
702+
}
703+
}
704+
694705
================================================================================
695706
TestManglePropsTypeScriptFeatures
696707
---------- /out/parameter-properties.js ----------

internal/js_parser/js_parser.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -2480,11 +2480,25 @@ func (p *parser) parsePropertyBinding() js_ast.PropertyBinding {
24802480
}
24812481
}
24822482

2483+
// These properties have special semantics in JavaScript. They must not be
2484+
// mangled or we could potentially fail to parse valid JavaScript syntax or
2485+
// generate invalid JavaScript syntax as output.
2486+
//
2487+
// This list is only intended to contain properties specific to the JavaScript
2488+
// language itself to avoid syntax errors in the generated output. It's not
2489+
// intended to contain properties for JavaScript APIs. Those must be provided
2490+
// by the user.
2491+
var permanentReservedProps = map[string]bool{
2492+
"__proto__": true,
2493+
"constructor": true,
2494+
"prototype": true,
2495+
}
2496+
24832497
func (p *parser) isMangledProp(name string) bool {
24842498
if p.options.mangleProps == nil {
24852499
return false
24862500
}
2487-
if p.options.mangleProps.MatchString(name) && name != "__proto__" && (p.options.reserveProps == nil || !p.options.reserveProps.MatchString(name)) {
2501+
if p.options.mangleProps.MatchString(name) && !permanentReservedProps[name] && (p.options.reserveProps == nil || !p.options.reserveProps.MatchString(name)) {
24882502
return true
24892503
}
24902504
reservedProps := p.reservedProps

0 commit comments

Comments
 (0)