Skip to content

Commit

Permalink
suggest default import when calling import ns
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Feb 11, 2021
1 parent f7d01de commit 4ab6a6d
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 22 deletions.
6 changes: 4 additions & 2 deletions internal/bundler/bundler_default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3905,9 +3905,11 @@ func TestCallImportNamespaceWarning(t *testing.T) {
AbsOutputDir: "/out",
OutputFormat: config.FormatESModule,
},
expectedScanLog: `js.js: warning: Cannot call "a" because it's an import namespace object, not a function
expectedScanLog: `js.js: warning: Calling "a" will crash at run-time because it's an import namespace object, not a function
js.js: note: Consider changing "a" to a default import instead
js.js: warning: Cannot construct "a" because it's an import namespace object, not a function
ts.ts: warning: Cannot call "a" because it's an import namespace object, not a function (make sure to enable TypeScript's "esModuleInterop" setting)
ts.ts: warning: Calling "a" will crash at run-time because it's an import namespace object, not a function (make sure to enable TypeScript's "esModuleInterop" setting)
ts.ts: note: Consider changing "a" to a default import instead
ts.ts: warning: Cannot construct "a" because it's an import namespace object, not a function (make sure to enable TypeScript's "esModuleInterop" setting)
`,
})
Expand Down
21 changes: 18 additions & 3 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -10813,9 +10813,24 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
if p.options.ts.Parse {
hint = " (make sure to enable TypeScript's \"esModuleInterop\" setting)"
}
p.log.AddRangeWarning(&p.source, r, fmt.Sprintf(
"Cannot call %q because it's an import namespace object, not a function%s",
p.symbols[id.Ref.InnerIndex].OriginalName, hint))
var notes []logger.MsgData
name := p.symbols[id.Ref.InnerIndex].OriginalName
if member, ok := p.moduleScope.Members[name]; ok && member.Ref == id.Ref {
if star := p.source.RangeOfOperatorBefore(member.Loc, "*"); star.Len > 0 {
if as := p.source.RangeOfOperatorBefore(member.Loc, "as"); as.Len > 0 && as.Loc.Start > star.Loc.Start {
note := logger.RangeData(&p.source,
logger.Range{Loc: star.Loc, Len: js_lexer.RangeOfIdentifier(p.source, member.Loc).End() - star.Loc.Start},
fmt.Sprintf("Consider changing %q to a default import instead", name))
note.Location.Suggestion = name
notes = []logger.MsgData{note}
}
}
}
p.log.AddRangeWarningWithNotes(&p.source, r, fmt.Sprintf(
"Calling %q will crash at run-time because it's an import namespace object, not a function%s",
p.symbols[id.Ref.InnerIndex].OriginalName, hint),
notes,
)
}
}

Expand Down
62 changes: 45 additions & 17 deletions internal/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,13 @@ type MsgData struct {
}

type MsgLocation struct {
File string
Namespace string
Line int // 1-based
Column int // 0-based, in bytes
Length int // in bytes
LineText string
File string
Namespace string
Line int // 1-based
Column int // 0-based, in bytes
Length int // in bytes
LineText string
Suggestion string
}

type Loc struct {
Expand Down Expand Up @@ -757,8 +758,12 @@ func marginWithLineText(maxMargin int, line int) string {
return fmt.Sprintf(" %s%s │ ", strings.Repeat(" ", maxMargin-len(number)), number)
}

func emptyMarginText(maxMargin int) string {
return fmt.Sprintf(" %s ╵ ", strings.Repeat(" ", maxMargin))
func emptyMarginText(maxMargin int, isLast bool) string {
space := strings.Repeat(" ", maxMargin)
if isLast {
return fmt.Sprintf(" %s ╵ ", space)
}
return fmt.Sprintf(" %s │ ", space)
}

func msgString(options OutputOptions, terminalInfo TerminalInfo, kind MsgKind, data MsgData, maxMargin int) string {
Expand Down Expand Up @@ -817,19 +822,40 @@ func msgString(options OutputOptions, terminalInfo TerminalInfo, kind MsgKind, d
d := detailStruct(data, terminalInfo, maxMargin)

if terminalInfo.UseColorEscapes {
return fmt.Sprintf("%s%s%s: %s%s: %s%s\n%s%s%s%s%s%s\n%s%s%s%s%s%s\n",
if d.Suggestion != "" {
return fmt.Sprintf("%s%s%s: %s%s: %s%s\n%s%s%s%s%s%s\n%s%s%s%s%s\n%s%s%s%s%s%s%s\n",
textColor, textIndent, d.Path,
kindColor, kind.String(),
textResetColor, d.Message,
colorResetDim, d.SourceBefore, colorGreen, d.SourceMarked, colorResetDim, d.SourceAfter,
emptyMarginText(maxMargin, false), d.Indent, colorGreen, d.Marker, colorResetDim,
emptyMarginText(maxMargin, true), d.Indent, colorGreen, d.Suggestion, colorResetDim,
d.ContentAfter, colorReset)
}

return fmt.Sprintf("%s%s%s: %s%s: %s%s\n%s%s%s%s%s%s\n%s%s%s%s%s%s%s\n",
textColor, textIndent, d.Path,
kindColor, kind.String(),
textResetColor, d.Message,
colorResetDim, d.SourceBefore, colorGreen, d.SourceMarked, colorResetDim, d.SourceAfter,
d.Indent, colorGreen, d.Marker,
colorResetDim, d.ContentAfter, colorReset)
emptyMarginText(maxMargin, true), d.Indent, colorGreen, d.Marker, colorResetDim,
d.ContentAfter, colorReset)
}

if d.Suggestion != "" {
return fmt.Sprintf("%s%s: %s: %s\n%s%s%s\n%s%s%s\n%s%s%s%s\n",
textIndent, d.Path, kind.String(), d.Message,
d.SourceBefore, d.SourceMarked, d.SourceAfter,
emptyMarginText(maxMargin, false), d.Indent, d.Marker,
emptyMarginText(maxMargin, true), d.Indent, d.Suggestion,
d.ContentAfter)
}

return fmt.Sprintf("%s%s: %s: %s\n%s%s%s\n%s%s%s\n",
return fmt.Sprintf("%s%s: %s: %s\n%s%s%s\n%s%s%s%s\n",
textIndent, d.Path, kind.String(), d.Message,
d.SourceBefore, d.SourceMarked, d.SourceAfter,
d.Indent, d.Marker, d.ContentAfter)
emptyMarginText(maxMargin, true), d.Indent, d.Marker,
d.ContentAfter)
}

type MsgDetail struct {
Expand All @@ -842,8 +868,9 @@ type MsgDetail struct {
SourceMarked string
SourceAfter string

Indent string
Marker string
Indent string
Marker string
Suggestion string

ContentAfter string
}
Expand Down Expand Up @@ -1038,8 +1065,9 @@ func detailStruct(data MsgData, terminalInfo TerminalInfo, maxMargin int) MsgDet
SourceMarked: lineText[markerStart:markerEnd],
SourceAfter: lineText[markerEnd:],

Indent: emptyMarginText(maxMargin) + indent,
Marker: marker,
Indent: indent,
Marker: marker,
Suggestion: loc.Suggestion,

ContentAfter: afterFirstLine,
}
Expand Down

0 comments on commit 4ab6a6d

Please sign in to comment.