Skip to content

Commit 7d50a50

Browse files
committed
implement late constant-folding of string enums
1 parent 1b29ac7 commit 7d50a50

File tree

4 files changed

+163
-5
lines changed

4 files changed

+163
-5
lines changed

internal/bundler_tests/bundler_dce_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3260,6 +3260,94 @@ func TestCrossModuleConstantFoldingNumber(t *testing.T) {
32603260
})
32613261
}
32623262

3263+
func TestCrossModuleConstantFoldingString(t *testing.T) {
3264+
dce_suite.expectBundled(t, bundled{
3265+
files: map[string]string{
3266+
"/enum-constants.ts": `
3267+
export enum x {
3268+
a = 'foo',
3269+
b = 'bar',
3270+
}
3271+
`,
3272+
"/enum-entry.ts": `
3273+
import { x } from './enum-constants'
3274+
console.log([
3275+
typeof x.b,
3276+
], [
3277+
x.a + x.b,
3278+
], [
3279+
x.a < x.b,
3280+
x.a > x.b,
3281+
x.a <= x.b,
3282+
x.a >= x.b,
3283+
x.a == x.b,
3284+
x.a != x.b,
3285+
x.a === x.b,
3286+
x.a !== x.b,
3287+
], [
3288+
x.a && x.b,
3289+
x.a || x.b,
3290+
x.a ?? x.b,
3291+
])
3292+
`,
3293+
3294+
"/const-constants.js": `
3295+
export const a = 'foo'
3296+
export const b = 'bar'
3297+
`,
3298+
"/const-entry.js": `
3299+
import { a, b } from './const-constants'
3300+
console.log([
3301+
typeof b,
3302+
], [
3303+
a + b,
3304+
], [
3305+
a < b,
3306+
a > b,
3307+
a <= b,
3308+
a >= b,
3309+
a == b,
3310+
a != b,
3311+
a === b,
3312+
a !== b,
3313+
], [
3314+
a && b,
3315+
a || b,
3316+
a ?? b,
3317+
])
3318+
`,
3319+
3320+
"/nested-constants.ts": `
3321+
export const a = 'foo'
3322+
export const b = 'bar'
3323+
export const c = 'baz'
3324+
export enum x {
3325+
a = 'FOO',
3326+
b = 'BAR',
3327+
c = 'BAZ',
3328+
}
3329+
`,
3330+
"/nested-entry.ts": `
3331+
import { a, b, c, x } from './nested-constants'
3332+
console.log({
3333+
'should be foobarbaz': a + b + c,
3334+
'should be FOOBARBAZ': x.a + x.b + x.c,
3335+
})
3336+
`,
3337+
},
3338+
entryPaths: []string{
3339+
"/enum-entry.ts",
3340+
"/const-entry.js",
3341+
"/nested-entry.ts",
3342+
},
3343+
options: config.Options{
3344+
Mode: config.ModeBundle,
3345+
AbsOutputDir: "/out",
3346+
MinifySyntax: true,
3347+
},
3348+
})
3349+
}
3350+
32633351
func TestMultipleDeclarationTreeShaking(t *testing.T) {
32643352
dce_suite.expectBundled(t, bundled{
32653353
files: map[string]string{

internal/bundler_tests/snapshots/snapshots_dce.txt

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,63 @@ console.log({
341341
"should be 32": 32
342342
});
343343

344+
================================================================================
345+
TestCrossModuleConstantFoldingString
346+
---------- /out/enum-entry.js ----------
347+
// enum-entry.ts
348+
console.log([
349+
typeof "bar" /* b */
350+
], [
351+
"foobar"
352+
], [
353+
!1,
354+
!0,
355+
!1,
356+
!0,
357+
!1,
358+
!0,
359+
!1,
360+
!0
361+
], [
362+
"foo" /* a */ && "bar" /* b */,
363+
"foo" /* a */ || "bar" /* b */,
364+
"foo" /* a */ ?? "bar" /* b */
365+
]);
366+
367+
---------- /out/const-entry.js ----------
368+
// const-constants.js
369+
var a = "foo", b = "bar";
370+
371+
// const-entry.js
372+
console.log([
373+
typeof b
374+
], [
375+
a + b
376+
], [
377+
a < b,
378+
a > b,
379+
a <= b,
380+
a >= b,
381+
a == b,
382+
a != b,
383+
a === b,
384+
a !== b
385+
], [
386+
a && b,
387+
a || b,
388+
a ?? b
389+
]);
390+
391+
---------- /out/nested-entry.js ----------
392+
// nested-constants.ts
393+
var a = "foo", b = "bar", c = "baz";
394+
395+
// nested-entry.ts
396+
console.log({
397+
"should be foobarbaz": a + b + c,
398+
"should be FOOBARBAZ": "FOOBARBAZ"
399+
});
400+
344401
================================================================================
345402
TestDCEClassStaticBlocks
346403
---------- /out.js ----------

internal/js_ast/js_ast_helpers.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,11 @@ func ShouldFoldBinaryOperatorWhenMinifying(binary *EBinary) bool {
11671167
return true
11681168
}
11691169

1170+
// String addition should pretty much always be more compact when folded
1171+
if _, _, ok := extractStringValues(binary.Left, binary.Right); ok {
1172+
return true
1173+
}
1174+
11701175
case BinOpSub:
11711176
// Subtraction of small-ish integers can definitely be folded without issues
11721177
// "3 - 1" => "2"
@@ -1215,6 +1220,9 @@ func FoldBinaryOperator(loc logger.Loc, e *EBinary) Expr {
12151220
if left, right, ok := extractNumericValues(e.Left, e.Right); ok {
12161221
return Expr{Loc: loc, Data: &ENumber{Value: left + right}}
12171222
}
1223+
if left, right, ok := extractStringValues(e.Left, e.Right); ok {
1224+
return Expr{Loc: loc, Data: &EString{Value: joinStrings(left, right)}}
1225+
}
12181226

12191227
case BinOpSub:
12201228
if left, right, ok := extractNumericValues(e.Left, e.Right); ok {

internal/js_printer/js_printer.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,17 +1758,22 @@ func (p *printer) lateConstantFoldUnaryOrBinaryExpr(expr js_ast.Expr) js_ast.Exp
17581758
}
17591759

17601760
case *js_ast.EDot:
1761-
if value, ok := p.tryToGetImportedEnumValue(e.Target, e.Name); ok && value.String == nil {
1762-
value := js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: value.Number}}
1761+
if value, ok := p.tryToGetImportedEnumValue(e.Target, e.Name); ok {
1762+
var inlinedValue js_ast.Expr
1763+
if value.String != nil {
1764+
inlinedValue = js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: value.String}}
1765+
} else {
1766+
inlinedValue = js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: value.Number}}
1767+
}
17631768

17641769
if strings.Contains(e.Name, "*/") {
17651770
// Don't wrap with a comment
1766-
return value
1771+
return inlinedValue
17671772
}
17681773

17691774
// Wrap with a comment
1770-
return js_ast.Expr{Loc: value.Loc, Data: &js_ast.EInlinedEnum{
1771-
Value: value,
1775+
return js_ast.Expr{Loc: inlinedValue.Loc, Data: &js_ast.EInlinedEnum{
1776+
Value: inlinedValue,
17721777
Comment: e.Name,
17731778
}}
17741779
}

0 commit comments

Comments
 (0)