Skip to content

Commit

Permalink
fix #378: source maps with out-of-order mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Sep 11, 2020
1 parent 670ae4a commit b7316d8
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

It is now an error to export an identifier using `export {foo}` if `foo` is not declared locally in the same file. This error matches the error that would happen at run-time if the code were to be evaluated in a JavaScript environment that supports ES6 module syntax. This is only an error in JavaScript. In TypeScript, the missing identifier is silently removed instead since it's assumed to be a type name.

* Handle source maps with out-of-order mappings ([#378](https://github.com/evanw/esbuild/issues/378))

Almost all tools that generate source maps write out the mappings in increasing order by generated position since the mappings are generated along with the output. However, some tools can apparently generate source maps with out-of-order mappings. It's impossible for generated line numbers to be out of order due to the way the source map format works, but it's possible for generated column numbers to be out of order. This release fixes this issue by sorting the mappings by generated position after parsing if necessary.

## 0.6.33

* Fix precedence of tagged template expressions ([#372](https://github.com/evanw/esbuild/issues/372))
Expand Down
28 changes: 24 additions & 4 deletions internal/parser/parser_sourcemap.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package parser

import (
"fmt"
"sort"
"strings"

"github.com/evanw/esbuild/internal/ast"
Expand Down Expand Up @@ -89,7 +90,7 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {
return nil
}

var mappings []sourcemap.Mapping
var mappings mappingArray
mappingsLen := len(mappingsRaw)
sourcesLen := len(sources)
generatedLine := 0
Expand All @@ -100,6 +101,7 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {
current := 0
errorText := ""
errorLen := 0
needSort := false

// Parse the mappings
for current < mappingsLen {
Expand All @@ -120,9 +122,7 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {
}
if generatedColumnDelta < 0 {
// This would mess up binary search
errorText = "Unexpected generated column decrease"
errorLen = i
break
needSort = true
}
generatedColumn += generatedColumnDelta
if generatedColumn < 0 {
Expand Down Expand Up @@ -225,9 +225,29 @@ func ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {
return nil
}

if needSort {
// If we get here, some mappings are out of order. Lines can't be out of
// order by construction but columns can. This is a pretty rare situation
// because almost all source map generators always write out mappings in
// order as they write the output instead of scrambling the order.
sort.Stable(mappings)
}

return &sourcemap.SourceMap{
Sources: sources,
SourcesContent: sourcesContent,
Mappings: mappings,
}
}

// This type is just so we can use Go's native sort function
type mappingArray []sourcemap.Mapping

func (a mappingArray) Len() int { return len(a) }
func (a mappingArray) Swap(i int, j int) { a[i], a[j] = a[j], a[i] }

func (a mappingArray) Less(i int, j int) bool {
ai := a[i]
aj := a[j]
return ai.GeneratedLine < aj.GeneratedLine || (ai.GeneratedLine == aj.GeneratedLine && ai.GeneratedColumn <= aj.GeneratedColumn)
}

0 comments on commit b7316d8

Please sign in to comment.