Skip to content

Commit

Permalink
fix invalid runtime code possible with supported
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Aug 29, 2022
1 parent d317a42 commit 632d8d1
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 55 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
* `generator=false` implies:
* `async-generator=false`

* `object-accessors=false` implies:
* `class-private-accessor=false`
* `class-private-static-accessor=false`

* `class-field=false` implies:
* `class-private-field=false`

Expand Down
34 changes: 12 additions & 22 deletions internal/bundler/bundler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2135,6 +2135,7 @@ func applyOptionDefaults(options *config.Options) {
// Automatically fix invalid configurations of unsupported features
fixInvalidUnsupportedJSFeatureOverrides(options, compat.AsyncAwait, compat.AsyncGenerator|compat.ForAwait|compat.TopLevelAwait)
fixInvalidUnsupportedJSFeatureOverrides(options, compat.Generator, compat.AsyncGenerator)
fixInvalidUnsupportedJSFeatureOverrides(options, compat.ObjectAccessors, compat.ClassPrivateAccessor|compat.ClassPrivateStaticAccessor)
fixInvalidUnsupportedJSFeatureOverrides(options, compat.ClassField, compat.ClassPrivateField)
fixInvalidUnsupportedJSFeatureOverrides(options, compat.ClassStaticField, compat.ClassPrivateStaticField)
fixInvalidUnsupportedJSFeatureOverrides(options, compat.Class,
Expand Down Expand Up @@ -2466,9 +2467,9 @@ func (b *Bundle) generateMetadataJSON(results []graph.OutputFile, allReachableFi
}

type runtimeCacheKey struct {
MinifySyntax bool
MinifyIdentifiers bool
ES6 bool
unsupportedJSFeatures compat.JSFeature
minifySyntax bool
minifyIdentifiers bool
}

type runtimeCache struct {
Expand All @@ -2481,17 +2482,13 @@ var globalRuntimeCache runtimeCache
func (cache *runtimeCache) parseRuntime(options *config.Options) (source logger.Source, runtimeAST js_ast.AST, ok bool) {
key := runtimeCacheKey{
// All configuration options that the runtime code depends on must go here
MinifySyntax: options.MinifySyntax,
MinifyIdentifiers: options.MinifyIdentifiers,
ES6: runtime.CanUseES6(options.UnsupportedJSFeatures),
unsupportedJSFeatures: options.UnsupportedJSFeatures,
minifySyntax: options.MinifySyntax,
minifyIdentifiers: options.MinifyIdentifiers,
}

// Determine which source to use
if key.ES6 {
source = runtime.ES6Source
} else {
source = runtime.ES5Source
}
source = runtime.Source(key.unsupportedJSFeatures)

// Cache hit?
(func() {
Expand All @@ -2506,19 +2503,12 @@ func (cache *runtimeCache) parseRuntime(options *config.Options) (source logger.
}

// Cache miss
var constraint int
if key.ES6 {
constraint = 2015
} else {
constraint = 5
}
log := logger.NewDeferLog(logger.DeferLogAll, nil)
runtimeAST, ok = js_parser.Parse(log, source, js_parser.OptionsFromConfig(&config.Options{
// These configuration options must only depend on the key
MinifySyntax: key.MinifySyntax,
MinifyIdentifiers: key.MinifyIdentifiers,
UnsupportedJSFeatures: compat.UnsupportedJSFeatures(
map[compat.Engine][]int{compat.ES: {constraint}}),
UnsupportedJSFeatures: key.unsupportedJSFeatures,
MinifySyntax: key.minifySyntax,
MinifyIdentifiers: key.minifyIdentifiers,

// Always do tree shaking for the runtime because we never want to
// include unnecessary runtime code
Expand All @@ -2527,7 +2517,7 @@ func (cache *runtimeCache) parseRuntime(options *config.Options) (source logger.
if log.HasErrors() {
msgs := "Internal error: failed to parse runtime:\n"
for _, msg := range log.Done() {
msgs += msg.String(logger.OutputOptions{}, logger.TerminalInfo{})
msgs += msg.String(logger.OutputOptions{IncludeSource: true}, logger.TerminalInfo{})
}
panic(msgs[:len(msgs)-1])
}
Expand Down
79 changes: 46 additions & 33 deletions internal/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ import (
// all code that references this index can be discovered easily.
const SourceIndex = uint32(0)

func CanUseES6(unsupportedFeatures compat.JSFeature) bool {
return !unsupportedFeatures.Has(compat.ConstAndLet) && !unsupportedFeatures.Has(compat.ForOf)
}

func code(isES6 bool) string {
func Source(unsupportedJSFeatures compat.JSFeature) logger.Source {
// Note: These helper functions used to be named similar things to the helper
// functions from the TypeScript compiler. However, people sometimes use these
// two projects in combination and TypeScript's implementation of these helpers
Expand Down Expand Up @@ -93,7 +89,7 @@ func code(isES6 bool) string {
`

// Avoid "of" when not using ES6
if isES6 {
if !unsupportedJSFeatures.Has(compat.ForOf) {
text += `
for (var prop of __getOwnPropSymbols(b)) {
`
Expand Down Expand Up @@ -143,7 +139,7 @@ func code(isES6 bool) string {
`

// Avoid "of" when not using ES6
if isES6 {
if !unsupportedJSFeatures.Has(compat.ForOf) {
text += `
for (var prop of __getOwnPropSymbols(source)) {
`
Expand Down Expand Up @@ -188,7 +184,7 @@ func code(isES6 bool) string {
`

// Avoid "let" when not using ES6
if isES6 {
if !unsupportedJSFeatures.Has(compat.ForOf) && !unsupportedJSFeatures.Has(compat.ConstAndLet) {
text += `
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
Expand Down Expand Up @@ -280,12 +276,25 @@ func code(isES6 bool) string {
setter ? setter.call(obj, value) : member.set(obj, value)
return value
}
export var __privateWrapper = (obj, member, setter, getter) => {
return {
`

if !unsupportedJSFeatures.Has(compat.ObjectAccessors) {
text += `
export var __privateWrapper = (obj, member, setter, getter) => ({
set _(value) { __privateSet(obj, member, value, setter) },
get _() { return __privateGet(obj, member, getter) },
}
}
})
`
} else {
text += `
export var __privateWrapper = (obj, member, setter, getter) => __defProp({}, '_', {
set: value => __privateSet(obj, member, value, setter),
get: () => __privateGet(obj, member, getter),
})
`
}

text += `
export var __privateMethod = (obj, member, method) => {
__accessCheck(obj, member, 'access private method')
return method
Expand All @@ -294,11 +303,25 @@ func code(isES6 bool) string {
// For "super" property accesses
export var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj)
export var __superSet = (cls, obj, key, val) => (__reflectSet(__getProtoOf(cls), key, val, obj), val)
export var __superWrapper = (cls, obj, key) => ({
get _() { return __superGet(cls, obj, key) },
set _(val) { __superSet(cls, obj, key, val) },
})
`

if !unsupportedJSFeatures.Has(compat.ObjectAccessors) {
text += `
export var __superWrapper = (cls, obj, key) => ({
get _() { return __superGet(cls, obj, key) },
set _(val) { __superSet(cls, obj, key, val) },
})
`
} else {
text += `
export var __superWrapper = (cls, obj, key) => __defProp({}, '_', {
get: () => __superGet(cls, obj, key),
set: val => __superSet(cls, obj, key, val),
})
`
}

text += `
// For lowering tagged template literals
export var __template = (cooked, raw) => __freeze(__defProp(cooked, 'raw', { value: __freeze(raw || cooked.slice()) }))
Expand Down Expand Up @@ -363,23 +386,13 @@ func code(isES6 bool) string {
})()
`

return text
}

var ES6Source = logger.Source{
Index: SourceIndex,
KeyPath: logger.Path{Text: "<runtime>"},
PrettyPath: "<runtime>",
IdentifierName: "runtime",
Contents: code(true /* isES6 */),
}

var ES5Source = logger.Source{
Index: SourceIndex,
KeyPath: logger.Path{Text: "<runtime>"},
PrettyPath: "<runtime>",
IdentifierName: "runtime",
Contents: code(false /* isES6 */),
return logger.Source{
Index: SourceIndex,
KeyPath: logger.Path{Text: "<runtime>"},
PrettyPath: "<runtime>",
IdentifierName: "runtime",
Contents: text,
}
}

// The TypeScript decorator transform behaves similar to the official
Expand Down

0 comments on commit 632d8d1

Please sign in to comment.