Skip to content

Commit

Permalink
generate "names" in source maps (#2415)
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jul 25, 2022
1 parent 98ab5e1 commit 7208846
Show file tree
Hide file tree
Showing 7 changed files with 499 additions and 107 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

* Emit `names` in source maps ([#1296](https://github.com/evanw/esbuild/issues/1296))

The [source map specification](https://sourcemaps.info/spec.html) includes an optional `names` field that can associate an identifier with a mapping entry. This can be used to record the original name for an identifier, which is useful if the identifier was renamed to something else in the generated code. When esbuild was originally written, this field wasn't widely used, but now there are some debuggers that make use of it to provide better debugging of minified code. With this release, esbuild now includes a `names` field in the source maps that it generates. To save space, the original name is only recorded when it's different from the final name.

* Update parser for arrow functions with initial default type parameters in `.tsx` files ([#2410](https://github.com/evanw/esbuild/issues/2410))

TypeScript 4.6 introduced a [change to the parsing of JSX syntax in `.tsx` files](https://github.com/microsoft/TypeScript/issues/47062). Now a `<` token followed by an identifier and then a `=` token is parsed as an arrow function with a default type parameter instead of as a JSX element. This release updates esbuild's parser to match TypeScript's parser.
Expand Down
34 changes: 33 additions & 1 deletion internal/bundler/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -5950,6 +5950,7 @@ func (c *linkerContext) generateSourceMapForChunk(
mappingsStart := j.Length()
prevEndState := sourcemap.SourceMapState{}
prevColumnOffset := 0
totalQuotedNameLen := 0
for _, result := range results {
chunk := result.sourceMapChunk
offset := result.generatedOffset
Expand All @@ -5971,6 +5972,7 @@ func (c *linkerContext) generateSourceMapForChunk(
SourceIndex: sourcesIndex,
GeneratedLine: offset.Lines,
GeneratedColumn: offset.Columns,
OriginalName: totalQuotedNameLen,
}
if offset.Lines == 0 {
startState.GeneratedColumn += prevColumnOffset
Expand All @@ -5980,9 +5982,24 @@ func (c *linkerContext) generateSourceMapForChunk(
sourcemap.AppendSourceMapChunk(&j, prevEndState, startState, chunk.Buffer)

// Generate the relative offset to start from next time
prevOriginalName := prevEndState.OriginalName
prevEndState = chunk.EndState
prevEndState.SourceIndex += sourcesIndex
if chunk.Buffer.FirstNameOffset.IsValid() {
prevEndState.OriginalName += totalQuotedNameLen
} else {
// It's possible for a chunk to have mappings but for none of those
// mappings to have an associated name. The name is optional and is
// omitted when the mapping is for a non-name token or if the final
// and original names are the same. In that case we need to restore
// the previous original name end state since it wasn't modified after
// all. If we don't do this, then files after this will adjust their
// name offsets assuming that the previous generated mapping has this
// file's offset, which is wrong.
prevEndState.OriginalName = prevOriginalName
}
prevColumnOffset = chunk.FinalGeneratedColumn
totalQuotedNameLen += len(chunk.QuotedNames)

// If this was all one line, include the column offset from the start
if prevEndState.GeneratedLine == 0 {
Expand All @@ -5992,8 +6009,23 @@ func (c *linkerContext) generateSourceMapForChunk(
}
mappingsEnd := j.Length()

// Write the names
isFirstName := true
j.AddString("\",\n \"names\": [")
for _, result := range results {
for _, quotedName := range result.sourceMapChunk.QuotedNames {
if isFirstName {
isFirstName = false
} else {
j.AddString(", ")
}
j.AddBytes(quotedName)
}
}
j.AddString("]")

// Finish the source map
j.AddString("\",\n \"names\": []\n}\n")
j.AddString("\n}\n")
bytes := j.Done()

if !canHaveShifts {
Expand Down
4 changes: 2 additions & 2 deletions internal/css_printer/css_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func Print(tree css_ast.AST, options Options) PrintResult {
p := printer{
options: options,
importRecords: tree.ImportRecords,
builder: sourcemap.MakeChunkBuilder(options.InputSourceMap, options.LineOffsetTables),
builder: sourcemap.MakeChunkBuilder(options.InputSourceMap, options.LineOffsetTables, options.ASCIIOnly),
}
for _, rule := range tree.Rules {
p.printRule(rule, 0, false)
Expand Down Expand Up @@ -78,7 +78,7 @@ func (p *printer) printRule(rule css_ast.Rule, indent int32, omitTrailingSemicol
}

if p.options.AddSourceMappings {
p.builder.AddSourceMapping(rule.Loc, p.css)
p.builder.AddSourceMapping(rule.Loc, "", p.css)
}

if !p.options.MinifyWhitespace {
Expand Down
30 changes: 28 additions & 2 deletions internal/js_parser/sourcemap_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"sort"

"github.com/evanw/esbuild/internal/ast"
"github.com/evanw/esbuild/internal/helpers"
"github.com/evanw/esbuild/internal/js_ast"
"github.com/evanw/esbuild/internal/logger"
Expand All @@ -26,6 +27,7 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {

var sources []string
var sourcesContent []sourcemap.SourceContent
var names []string
var mappingsRaw []uint16
var mappingsStart int32
hasVersion := false
Expand Down Expand Up @@ -75,6 +77,18 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {
}
}
}

case "names":
if value, ok := prop.ValueOrNil.Data.(*js_ast.EArray); ok {
names = nil
for _, item := range value.Items {
if element, ok := item.Data.(*js_ast.EString); ok {
names = append(names, helpers.UTF16ToString(element.Value))
} else {
names = append(names, "")
}
}
}
}
}

Expand All @@ -91,11 +105,13 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {
var mappings mappingArray
mappingsLen := len(mappingsRaw)
sourcesLen := len(sources)
namesLen := len(names)
var generatedLine int32
var generatedColumn int32
var sourceIndex int32
var originalLine int32
var originalColumn int32
var originalName int32
current := 0
errorText := ""
errorLen := 0
Expand Down Expand Up @@ -190,8 +206,16 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {
}
current += i

// Ignore the optional name index
if _, i, ok := sourcemap.DecodeVLQUTF16(mappingsRaw[current:]); ok {
// Read the original name
var optionalName ast.Index32
if originalNameDelta, i, ok := sourcemap.DecodeVLQUTF16(mappingsRaw[current:]); ok {
originalName += originalNameDelta
if originalName < 0 || originalName >= int32(namesLen) {
errorText = fmt.Sprintf("Invalid name index value: %d", originalName)
errorLen = i
break
}
optionalName = ast.MakeIndex32(uint32(originalName))
current += i
}

Expand All @@ -213,6 +237,7 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {
SourceIndex: sourceIndex,
OriginalLine: originalLine,
OriginalColumn: originalColumn,
OriginalName: optionalName,
})
}

Expand All @@ -235,6 +260,7 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {
Sources: sources,
SourcesContent: sourcesContent,
Mappings: mappings,
Names: names,
}
}

Expand Down
Loading

0 comments on commit 7208846

Please sign in to comment.