Skip to content

Commit 68573ab

Browse files
committed
internal: factor out key format for define map
1 parent 364e5b9 commit 68573ab

File tree

1 file changed

+52
-35
lines changed

1 file changed

+52
-35
lines changed

pkg/api/api_impl.go

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,18 @@ func validateJSXExpr(log logger.Log, text string, name string) config.DefineExpr
524524
return config.DefineExpr{}
525525
}
526526

527+
// This returns an arbitrary but unique key for each unique array of strings
528+
func mapKeyForDefine(parts []string) string {
529+
var sb strings.Builder
530+
var n [4]byte
531+
for _, part := range parts {
532+
binary.LittleEndian.PutUint32(n[:], uint32(len(part)))
533+
sb.Write(n[:])
534+
sb.WriteString(part)
535+
}
536+
return sb.String()
537+
}
538+
527539
func validateDefines(
528540
log logger.Log,
529541
defines map[string]string,
@@ -533,13 +545,26 @@ func validateDefines(
533545
minify bool,
534546
drop Drop,
535547
) (*config.ProcessedDefines, []config.InjectedDefine) {
548+
// Sort injected defines for determinism, since the imports will be injected
549+
// into every file in the order that we return them from this function
550+
sortedKeys := make([]string, 0, len(defines))
551+
for key := range defines {
552+
sortedKeys = append(sortedKeys, key)
553+
}
554+
sort.Strings(sortedKeys)
555+
536556
rawDefines := make(map[string]config.DefineData)
537-
var valueToInject map[string]config.InjectedDefine
538-
var definesToInject []string
557+
nodeEnvParts := []string{"process", "env", "NODE_ENV"}
558+
nodeEnvMapKey := mapKeyForDefine(nodeEnvParts)
559+
var injectedDefines []config.InjectedDefine
560+
561+
for _, key := range sortedKeys {
562+
value := defines[key]
563+
keyParts := strings.Split(key, ".")
564+
mapKey := mapKeyForDefine(keyParts)
539565

540-
for key, value := range defines {
541566
// The key must be a dot-separated identifier list
542-
for _, part := range strings.Split(key, ".") {
567+
for _, part := range keyParts {
543568
if !js_ast.IsIdentifier(part) {
544569
if part == key {
545570
log.AddError(nil, logger.Range{}, fmt.Sprintf("The define key %q must be a valid identifier", key))
@@ -555,10 +580,10 @@ func validateDefines(
555580

556581
// Define simple expressions
557582
if defineExpr.Constant != nil || len(defineExpr.Parts) > 0 {
558-
rawDefines[key] = config.DefineData{DefineExpr: &defineExpr}
583+
rawDefines[mapKey] = config.DefineData{KeyParts: keyParts, DefineExpr: &defineExpr}
559584

560585
// Try to be helpful for common mistakes
561-
if len(defineExpr.Parts) == 1 && key == "process.env.NODE_ENV" {
586+
if len(defineExpr.Parts) == 1 && mapKey == nodeEnvMapKey {
562587
data := logger.MsgData{
563588
Text: fmt.Sprintf("%q is defined as an identifier instead of a string (surround %q with quotes to get a string)", key, value),
564589
}
@@ -606,83 +631,75 @@ func validateDefines(
606631

607632
// Inject complex expressions
608633
if injectExpr != nil {
609-
definesToInject = append(definesToInject, key)
610-
if valueToInject == nil {
611-
valueToInject = make(map[string]config.InjectedDefine)
612-
}
613-
valueToInject[key] = config.InjectedDefine{
634+
index := ast.MakeIndex32(uint32(len(injectedDefines)))
635+
injectedDefines = append(injectedDefines, config.InjectedDefine{
614636
Source: logger.Source{Contents: value},
615637
Data: injectExpr,
616638
Name: key,
617-
}
639+
})
640+
rawDefines[mapKey] = config.DefineData{KeyParts: keyParts, DefineExpr: &config.DefineExpr{InjectedDefineIndex: index}}
618641
continue
619642
}
620643

621644
// Anything else is unsupported
622645
log.AddError(nil, logger.Range{}, fmt.Sprintf("Invalid define value (must be an entity name or valid JSON syntax): %s", value))
623646
}
624647

625-
// Sort injected defines for determinism, since the imports will be injected
626-
// into every file in the order that we return them from this function
627-
var injectedDefines []config.InjectedDefine
628-
if len(definesToInject) > 0 {
629-
injectedDefines = make([]config.InjectedDefine, len(definesToInject))
630-
sort.Strings(definesToInject)
631-
for i, key := range definesToInject {
632-
injectedDefines[i] = valueToInject[key]
633-
rawDefines[key] = config.DefineData{DefineExpr: &config.DefineExpr{InjectedDefineIndex: ast.MakeIndex32(uint32(i))}}
634-
}
635-
}
636-
637648
// If we're bundling for the browser, add a special-cased define for
638649
// "process.env.NODE_ENV" that is "development" when not minifying and
639650
// "production" when minifying. This is a convention from the React world
640651
// that must be handled to avoid all React code crashing instantly. This
641652
// is only done if it's not already defined so that you can override it if
642653
// necessary.
643654
if isBuildAPI && platform == config.PlatformBrowser {
644-
if _, process := rawDefines["process"]; !process {
645-
if _, processEnv := rawDefines["process.env"]; !processEnv {
646-
if _, processEnvNodeEnv := rawDefines["process.env.NODE_ENV"]; !processEnvNodeEnv {
655+
if _, process := rawDefines[mapKeyForDefine([]string{"process"})]; !process {
656+
if _, processEnv := rawDefines[mapKeyForDefine([]string{"process.env"})]; !processEnv {
657+
if _, processEnvNodeEnv := rawDefines[nodeEnvMapKey]; !processEnvNodeEnv {
647658
var value []uint16
648659
if minify {
649660
value = helpers.StringToUTF16("production")
650661
} else {
651662
value = helpers.StringToUTF16("development")
652663
}
653-
rawDefines["process.env.NODE_ENV"] = config.DefineData{DefineExpr: &config.DefineExpr{Constant: &js_ast.EString{Value: value}}}
664+
rawDefines[nodeEnvMapKey] = config.DefineData{KeyParts: nodeEnvParts, DefineExpr: &config.DefineExpr{Constant: &js_ast.EString{Value: value}}}
654665
}
655666
}
656667
}
657668
}
658669

659670
// If we're dropping all console API calls, replace each one with undefined
660671
if (drop & DropConsole) != 0 {
661-
define := rawDefines["console"]
672+
consoleParts := []string{"console"}
673+
consoleMapKey := mapKeyForDefine(consoleParts)
674+
define := rawDefines[consoleMapKey]
675+
define.KeyParts = consoleParts
662676
define.Flags |= config.MethodCallsMustBeReplacedWithUndefined
663-
rawDefines["console"] = define
677+
rawDefines[consoleMapKey] = define
664678
}
665679

666680
for _, key := range pureFns {
681+
keyParts := strings.Split(key, ".")
682+
mapKey := mapKeyForDefine(keyParts)
683+
667684
// The key must be a dot-separated identifier list
668-
for _, part := range strings.Split(key, ".") {
685+
for _, part := range keyParts {
669686
if !js_ast.IsIdentifier(part) {
670687
log.AddError(nil, logger.Range{}, fmt.Sprintf("Invalid pure function: %q", key))
671688
continue
672689
}
673690
}
674691

675692
// Merge with any previously-specified defines
676-
define := rawDefines[key]
693+
define := rawDefines[mapKey]
694+
define.KeyParts = keyParts
677695
define.Flags |= config.CallCanBeUnwrappedIfUnused
678-
rawDefines[key] = define
696+
rawDefines[mapKey] = define
679697
}
680698

681699
// Processing defines is expensive. Process them once here so the same object
682700
// can be shared between all parsers we create using these arguments.
683701
definesArray := make([]config.DefineData, 0, len(rawDefines))
684-
for key, define := range rawDefines {
685-
define.KeyParts = strings.Split(key, ".")
702+
for _, define := range rawDefines {
686703
definesArray = append(definesArray, define)
687704
}
688705
processed := config.ProcessDefines(definesArray)

0 commit comments

Comments
 (0)