remove unused packages
This commit is contained in:
parent
78201db012
commit
f1795ab4d0
@ -1,252 +0,0 @@
|
||||
package sourcemap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"iter"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
)
|
||||
|
||||
type Mapping struct {
|
||||
GeneratedLine int
|
||||
GeneratedCharacter int
|
||||
SourceIndex SourceIndex
|
||||
SourceLine int
|
||||
SourceCharacter int
|
||||
NameIndex NameIndex
|
||||
}
|
||||
|
||||
func (m *Mapping) Equals(other *Mapping) bool {
|
||||
return m == other || m.GeneratedLine == other.GeneratedLine &&
|
||||
m.GeneratedCharacter == other.GeneratedCharacter &&
|
||||
m.SourceIndex == other.SourceIndex &&
|
||||
m.SourceLine == other.SourceLine &&
|
||||
m.SourceCharacter == other.SourceCharacter &&
|
||||
m.NameIndex == other.NameIndex
|
||||
}
|
||||
|
||||
func (m *Mapping) IsSourceMapping() bool {
|
||||
return m.SourceIndex != MissingSource &&
|
||||
m.SourceLine != MissingLineOrColumn &&
|
||||
m.SourceCharacter != MissingLineOrColumn
|
||||
}
|
||||
|
||||
const (
|
||||
MissingSource SourceIndex = -1
|
||||
MissingName NameIndex = -1
|
||||
MissingLineOrColumn int = -1
|
||||
)
|
||||
|
||||
type MappingsDecoder struct {
|
||||
mappings string
|
||||
done bool
|
||||
pos int
|
||||
generatedLine int
|
||||
generatedCharacter int
|
||||
sourceIndex SourceIndex
|
||||
sourceLine int
|
||||
sourceCharacter int
|
||||
nameIndex NameIndex
|
||||
error error
|
||||
mappingPool core.Pool[Mapping]
|
||||
}
|
||||
|
||||
func DecodeMappings(mappings string) *MappingsDecoder {
|
||||
return &MappingsDecoder{mappings: mappings}
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) MappingsString() string {
|
||||
return d.mappings
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) Pos() int {
|
||||
return d.pos
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) Error() error {
|
||||
return d.error
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) State() *Mapping {
|
||||
return d.captureMapping(true /*hasSource*/, true /*hasName*/)
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) Values() iter.Seq[*Mapping] {
|
||||
return func(yield func(*Mapping) bool) {
|
||||
for value, done := d.Next(); !done; value, done = d.Next() {
|
||||
if !yield(value) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) Next() (value *Mapping, done bool) {
|
||||
for !d.done && d.pos < len(d.mappings) {
|
||||
ch := d.mappings[d.pos]
|
||||
if ch == ';' {
|
||||
// new line
|
||||
d.generatedLine++
|
||||
d.generatedCharacter = 0
|
||||
d.pos++
|
||||
continue
|
||||
}
|
||||
|
||||
if ch == ',' {
|
||||
// Next entry is on same line - no action needed
|
||||
d.pos++
|
||||
continue
|
||||
}
|
||||
|
||||
hasSource := false
|
||||
hasName := false
|
||||
d.generatedCharacter += d.base64VLQFormatDecode()
|
||||
if d.hasReportedError() {
|
||||
return d.stopIterating()
|
||||
}
|
||||
if d.generatedCharacter < 0 {
|
||||
return d.setErrorAndStopIterating("Invalid generatedCharacter found")
|
||||
}
|
||||
|
||||
if !d.isSourceMappingSegmentEnd() {
|
||||
hasSource = true
|
||||
|
||||
d.sourceIndex += SourceIndex(d.base64VLQFormatDecode())
|
||||
if d.hasReportedError() {
|
||||
return d.stopIterating()
|
||||
}
|
||||
if d.sourceIndex < 0 {
|
||||
return d.setErrorAndStopIterating("Invalid sourceIndex found")
|
||||
}
|
||||
if d.isSourceMappingSegmentEnd() {
|
||||
return d.setErrorAndStopIterating("Unsupported Format: No entries after sourceIndex")
|
||||
}
|
||||
|
||||
d.sourceLine += d.base64VLQFormatDecode()
|
||||
if d.hasReportedError() {
|
||||
return d.stopIterating()
|
||||
}
|
||||
if d.sourceLine < 0 {
|
||||
return d.setErrorAndStopIterating("Invalid sourceLine found")
|
||||
}
|
||||
if d.isSourceMappingSegmentEnd() {
|
||||
return d.setErrorAndStopIterating("Unsupported Format: No entries after sourceLine")
|
||||
}
|
||||
|
||||
d.sourceCharacter += d.base64VLQFormatDecode()
|
||||
if d.hasReportedError() {
|
||||
return d.stopIterating()
|
||||
}
|
||||
if d.sourceCharacter < 0 {
|
||||
return d.setErrorAndStopIterating("Invalid sourceCharacter found")
|
||||
}
|
||||
|
||||
if !d.isSourceMappingSegmentEnd() {
|
||||
hasName = true
|
||||
d.nameIndex += NameIndex(d.base64VLQFormatDecode())
|
||||
if d.hasReportedError() {
|
||||
return d.stopIterating()
|
||||
}
|
||||
if d.nameIndex < 0 {
|
||||
return d.setErrorAndStopIterating("Invalid nameIndex found")
|
||||
}
|
||||
|
||||
if !d.isSourceMappingSegmentEnd() {
|
||||
return d.setErrorAndStopIterating("Unsupported Error Format: Entries after nameIndex")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return d.captureMapping(hasSource, hasName), false
|
||||
}
|
||||
|
||||
return d.stopIterating()
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) captureMapping(hasSource bool, hasName bool) *Mapping {
|
||||
mapping := d.mappingPool.New()
|
||||
mapping.GeneratedLine = d.generatedLine
|
||||
mapping.GeneratedCharacter = d.generatedCharacter
|
||||
mapping.SourceIndex = core.IfElse(hasSource, d.sourceIndex, MissingSource)
|
||||
mapping.SourceLine = core.IfElse(hasSource, d.sourceLine, MissingLineOrColumn)
|
||||
mapping.SourceCharacter = core.IfElse(hasSource, d.sourceCharacter, MissingLineOrColumn)
|
||||
mapping.NameIndex = core.IfElse(hasName, d.nameIndex, MissingName)
|
||||
return mapping
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) stopIterating() (*Mapping, bool) {
|
||||
d.done = true
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) setError(err string) {
|
||||
d.error = errors.New(err)
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) setErrorAndStopIterating(err string) (*Mapping, bool) {
|
||||
d.setError(err)
|
||||
return d.stopIterating()
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) hasReportedError() bool {
|
||||
return d.error != nil
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) isSourceMappingSegmentEnd() bool {
|
||||
return d.pos == len(d.mappings) || d.mappings[d.pos] == ',' || d.mappings[d.pos] == ';'
|
||||
}
|
||||
|
||||
func (d *MappingsDecoder) base64VLQFormatDecode() int {
|
||||
moreDigits := true
|
||||
shiftCount := 0
|
||||
value := 0
|
||||
for ; moreDigits; d.pos++ {
|
||||
if d.pos >= len(d.mappings) {
|
||||
d.setError("Error in decoding base64VLQFormatDecode, past the mapping string")
|
||||
return -1
|
||||
}
|
||||
|
||||
// 6 digit number
|
||||
currentByte := base64FormatDecode(d.mappings[d.pos])
|
||||
if currentByte == -1 {
|
||||
d.setError("Invalid character in VLQ")
|
||||
return -1
|
||||
}
|
||||
|
||||
// If msb is set, we still have more bits to continue
|
||||
moreDigits = (currentByte & 32) != 0
|
||||
|
||||
// least significant 5 bits are the next msbs in the final value.
|
||||
value = value | ((currentByte & 31) << shiftCount)
|
||||
shiftCount += 5
|
||||
}
|
||||
|
||||
// Least significant bit if 1 represents negative and rest of the msb is actual absolute value
|
||||
if (value & 1) == 0 {
|
||||
// + number
|
||||
value = value >> 1
|
||||
} else {
|
||||
// - number
|
||||
value = value >> 1
|
||||
value = -value
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func base64FormatDecode(ch byte) int {
|
||||
switch {
|
||||
case ch >= 'A' && ch <= 'Z':
|
||||
return int(ch - 'A')
|
||||
case ch >= 'a' && ch <= 'z':
|
||||
return int(ch - 'a' + 26)
|
||||
case ch >= '0' && ch <= '9':
|
||||
return int(ch - '0' + 52)
|
||||
case ch == '+':
|
||||
return 62
|
||||
case ch == '/':
|
||||
return 63
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
@ -1,360 +0,0 @@
|
||||
package sourcemap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
||||
"github.com/go-json-experiment/json"
|
||||
)
|
||||
|
||||
type (
|
||||
SourceIndex int
|
||||
NameIndex int
|
||||
)
|
||||
|
||||
const (
|
||||
sourceIndexNotSet SourceIndex = -1
|
||||
nameIndexNotSet NameIndex = -1
|
||||
notSet int = -1
|
||||
)
|
||||
|
||||
type Generator struct {
|
||||
pathOptions tspath.ComparePathsOptions
|
||||
file string
|
||||
sourceRoot string
|
||||
sourcesDirectoryPath string
|
||||
rawSources []string
|
||||
sources []string
|
||||
sourceToSourceIndexMap map[string]SourceIndex
|
||||
sourcesContent []*string
|
||||
names []string
|
||||
nameToNameIndexMap map[string]NameIndex
|
||||
mappings strings.Builder
|
||||
lastGeneratedLine int
|
||||
lastGeneratedCharacter int
|
||||
lastSourceIndex SourceIndex
|
||||
lastSourceLine int
|
||||
lastSourceCharacter int
|
||||
lastNameIndex NameIndex
|
||||
hasLast bool
|
||||
pendingGeneratedLine int
|
||||
pendingGeneratedCharacter int
|
||||
pendingSourceIndex SourceIndex
|
||||
pendingSourceLine int
|
||||
pendingSourceCharacter int
|
||||
pendingNameIndex NameIndex
|
||||
hasPending bool
|
||||
hasPendingSource bool
|
||||
hasPendingName bool
|
||||
}
|
||||
|
||||
type RawSourceMap struct {
|
||||
Version int `json:"version"`
|
||||
File string `json:"file"`
|
||||
SourceRoot string `json:"sourceRoot"`
|
||||
Sources []string `json:"sources"`
|
||||
Names []string `json:"names"`
|
||||
Mappings string `json:"mappings"`
|
||||
SourcesContent []*string `json:"sourcesContent,omitzero"`
|
||||
}
|
||||
|
||||
func NewGenerator(file string, sourceRoot string, sourcesDirectoryPath string, options tspath.ComparePathsOptions) *Generator {
|
||||
return &Generator{
|
||||
file: file,
|
||||
sourceRoot: sourceRoot,
|
||||
sourcesDirectoryPath: sourcesDirectoryPath,
|
||||
pathOptions: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (gen *Generator) Sources() []string { return gen.rawSources }
|
||||
|
||||
// Adds a source to the source map
|
||||
func (gen *Generator) AddSource(fileName string) SourceIndex {
|
||||
source := tspath.GetRelativePathToDirectoryOrUrl(
|
||||
gen.sourcesDirectoryPath,
|
||||
fileName,
|
||||
true, /*isAbsolutePathAnUrl*/
|
||||
gen.pathOptions,
|
||||
)
|
||||
|
||||
sourceIndex, found := gen.sourceToSourceIndexMap[source]
|
||||
if !found {
|
||||
sourceIndex = SourceIndex(len(gen.sources))
|
||||
gen.sources = append(gen.sources, source)
|
||||
gen.rawSources = append(gen.rawSources, fileName)
|
||||
if gen.sourceToSourceIndexMap == nil {
|
||||
gen.sourceToSourceIndexMap = make(map[string]SourceIndex)
|
||||
}
|
||||
gen.sourceToSourceIndexMap[source] = sourceIndex
|
||||
}
|
||||
|
||||
return sourceIndex
|
||||
}
|
||||
|
||||
// Sets the content for a source
|
||||
func (gen *Generator) SetSourceContent(sourceIndex SourceIndex, content string) error {
|
||||
if sourceIndex < 0 || int(sourceIndex) >= len(gen.sources) {
|
||||
return errors.New("sourceIndex is out of range")
|
||||
}
|
||||
for len(gen.sourcesContent) <= int(sourceIndex) {
|
||||
gen.sourcesContent = append(gen.sourcesContent, nil)
|
||||
}
|
||||
gen.sourcesContent[sourceIndex] = &content
|
||||
return nil
|
||||
}
|
||||
|
||||
// Declares a name in the source map, returning the index of the name
|
||||
func (gen *Generator) AddName(name string) NameIndex {
|
||||
nameIndex, found := gen.nameToNameIndexMap[name]
|
||||
if !found {
|
||||
nameIndex = NameIndex(len(gen.names))
|
||||
gen.names = append(gen.names, name)
|
||||
if gen.nameToNameIndexMap == nil {
|
||||
gen.nameToNameIndexMap = make(map[string]NameIndex)
|
||||
}
|
||||
gen.nameToNameIndexMap[name] = nameIndex
|
||||
}
|
||||
return nameIndex
|
||||
}
|
||||
|
||||
func (gen *Generator) isNewGeneratedPosition(generatedLine int, generatedCharacter int) bool {
|
||||
return !gen.hasPending ||
|
||||
gen.pendingGeneratedLine != generatedLine ||
|
||||
gen.pendingGeneratedCharacter != generatedCharacter
|
||||
}
|
||||
|
||||
func (gen *Generator) isBacktrackingSourcePosition(sourceIndex SourceIndex, sourceLine int, sourceCharacter int) bool {
|
||||
return sourceIndex != sourceIndexNotSet &&
|
||||
sourceLine != notSet &&
|
||||
sourceCharacter != notSet &&
|
||||
gen.pendingSourceIndex == sourceIndex &&
|
||||
(gen.pendingSourceLine > sourceLine ||
|
||||
gen.pendingSourceLine == sourceLine && gen.pendingSourceCharacter > sourceCharacter)
|
||||
}
|
||||
|
||||
func (gen *Generator) shouldCommitMapping() bool {
|
||||
return gen.hasPending && (!gen.hasLast ||
|
||||
gen.lastGeneratedLine != gen.pendingGeneratedLine ||
|
||||
gen.lastGeneratedCharacter != gen.pendingGeneratedCharacter ||
|
||||
gen.lastSourceIndex != gen.pendingSourceIndex ||
|
||||
gen.lastSourceLine != gen.pendingSourceLine ||
|
||||
gen.lastSourceCharacter != gen.pendingSourceCharacter ||
|
||||
gen.lastNameIndex != gen.pendingNameIndex)
|
||||
}
|
||||
|
||||
func (gen *Generator) appendMappingCharCode(charCode rune) {
|
||||
gen.mappings.WriteRune(charCode)
|
||||
}
|
||||
|
||||
func (gen *Generator) appendBase64VLQ(inValue int) {
|
||||
// Add a new least significant bit that has the sign of the value.
|
||||
// if negative number the least significant bit that gets added to the number has value 1
|
||||
// else least significant bit value that gets added is 0
|
||||
// eg. -1 changes to binary : 01 [1] => 3
|
||||
// +1 changes to binary : 01 [0] => 2
|
||||
if inValue < 0 {
|
||||
inValue = ((-inValue) << 1) + 1
|
||||
} else {
|
||||
inValue = inValue << 1
|
||||
}
|
||||
|
||||
// Encode 5 bits at a time starting from least significant bits
|
||||
for {
|
||||
currentDigit := inValue & 31 // 11111
|
||||
inValue = inValue >> 5
|
||||
if inValue > 0 {
|
||||
// There are still more digits to decode, set the msb (6th bit)
|
||||
currentDigit = currentDigit | 32
|
||||
}
|
||||
gen.appendMappingCharCode(base64FormatEncode(currentDigit))
|
||||
if inValue <= 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (gen *Generator) commitPendingMapping() {
|
||||
if !gen.shouldCommitMapping() {
|
||||
return
|
||||
}
|
||||
|
||||
// Line/Comma delimiters
|
||||
if gen.lastGeneratedLine < gen.pendingGeneratedLine {
|
||||
// Emit line delimiters
|
||||
for {
|
||||
gen.appendMappingCharCode(';')
|
||||
gen.lastGeneratedLine++
|
||||
if gen.lastGeneratedLine >= gen.pendingGeneratedLine {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Only need to set this once
|
||||
gen.lastGeneratedCharacter = 0
|
||||
} else {
|
||||
if gen.lastGeneratedLine != gen.pendingGeneratedLine {
|
||||
// panic rather than error as an invariant has been violated
|
||||
panic("generatedLine cannot backtrack")
|
||||
}
|
||||
// Emit comma to separate the entry
|
||||
if gen.hasLast {
|
||||
gen.appendMappingCharCode(',')
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Relative generated character
|
||||
gen.appendBase64VLQ(gen.pendingGeneratedCharacter - gen.lastGeneratedCharacter)
|
||||
gen.lastGeneratedCharacter = gen.pendingGeneratedCharacter
|
||||
|
||||
if gen.hasPendingSource {
|
||||
// 2. Relative sourceIndex
|
||||
gen.appendBase64VLQ(int(gen.pendingSourceIndex - gen.lastSourceIndex))
|
||||
gen.lastSourceIndex = gen.pendingSourceIndex
|
||||
|
||||
// 3. Relative source line
|
||||
gen.appendBase64VLQ(gen.pendingSourceLine - gen.lastSourceLine)
|
||||
gen.lastSourceLine = gen.pendingSourceLine
|
||||
|
||||
// 4. Relative source character
|
||||
gen.appendBase64VLQ(gen.pendingSourceCharacter - gen.lastSourceCharacter)
|
||||
gen.lastSourceCharacter = gen.pendingSourceCharacter
|
||||
|
||||
if gen.hasPendingName {
|
||||
// 5. Relative nameIndex
|
||||
gen.appendBase64VLQ(int(gen.pendingNameIndex - gen.lastNameIndex))
|
||||
gen.lastNameIndex = gen.pendingNameIndex
|
||||
}
|
||||
}
|
||||
|
||||
gen.hasLast = true
|
||||
}
|
||||
|
||||
func (gen *Generator) addMapping(generatedLine int, generatedCharacter int, sourceIndex SourceIndex, sourceLine int, sourceCharacter int, nameIndex NameIndex) {
|
||||
if gen.isNewGeneratedPosition(generatedLine, generatedCharacter) ||
|
||||
gen.isBacktrackingSourcePosition(sourceIndex, sourceLine, sourceCharacter) {
|
||||
gen.commitPendingMapping()
|
||||
gen.pendingGeneratedLine = generatedLine
|
||||
gen.pendingGeneratedCharacter = generatedCharacter
|
||||
gen.hasPendingSource = false
|
||||
gen.hasPendingName = false
|
||||
gen.hasPending = true
|
||||
}
|
||||
|
||||
if sourceIndex != sourceIndexNotSet && sourceLine != notSet && sourceCharacter != notSet {
|
||||
gen.pendingSourceIndex = sourceIndex
|
||||
gen.pendingSourceLine = sourceLine
|
||||
gen.pendingSourceCharacter = sourceCharacter
|
||||
gen.hasPendingSource = true
|
||||
if nameIndex != nameIndexNotSet {
|
||||
gen.pendingNameIndex = nameIndex
|
||||
gen.hasPendingName = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a mapping without source information
|
||||
func (gen *Generator) AddGeneratedMapping(generatedLine int, generatedCharacter int) error {
|
||||
if generatedLine < gen.pendingGeneratedLine {
|
||||
return errors.New("generatedLine cannot backtrack")
|
||||
}
|
||||
if generatedCharacter < 0 {
|
||||
return errors.New("generatedCharacter cannot be negative")
|
||||
}
|
||||
gen.addMapping(generatedLine, generatedCharacter, sourceIndexNotSet, notSet /*sourceLine*/, notSet /*sourceCharacter*/, nameIndexNotSet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Adds a mapping with source information
|
||||
func (gen *Generator) AddSourceMapping(generatedLine int, generatedCharacter int, sourceIndex SourceIndex, sourceLine int, sourceCharacter int) error {
|
||||
if generatedLine < gen.pendingGeneratedLine {
|
||||
return errors.New("generatedLine cannot backtrack")
|
||||
}
|
||||
if generatedCharacter < 0 {
|
||||
return errors.New("generatedCharacter cannot be negative")
|
||||
}
|
||||
if sourceIndex < 0 || int(sourceIndex) >= len(gen.sources) {
|
||||
return errors.New("sourceIndex is out of range")
|
||||
}
|
||||
if sourceLine < 0 {
|
||||
return errors.New("sourceLine cannot be negative")
|
||||
}
|
||||
if sourceCharacter < 0 {
|
||||
return errors.New("sourceCharacter cannot be negative")
|
||||
}
|
||||
gen.addMapping(generatedLine, generatedCharacter, sourceIndex, sourceLine, sourceCharacter, nameIndexNotSet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Adds a mapping with source and name information
|
||||
func (gen *Generator) AddNamedSourceMapping(generatedLine int, generatedCharacter int, sourceIndex SourceIndex, sourceLine int, sourceCharacter int, nameIndex NameIndex) error {
|
||||
if generatedLine < gen.pendingGeneratedLine {
|
||||
return errors.New("generatedLine cannot backtrack")
|
||||
}
|
||||
if generatedCharacter < 0 {
|
||||
return errors.New("generatedCharacter cannot be negative")
|
||||
}
|
||||
if sourceIndex < 0 || int(sourceIndex) >= len(gen.sources) {
|
||||
return errors.New("sourceIndex is out of range")
|
||||
}
|
||||
if sourceLine < 0 {
|
||||
return errors.New("sourceLine cannot be negative")
|
||||
}
|
||||
if sourceCharacter < 0 {
|
||||
return errors.New("sourceCharacter cannot be negative")
|
||||
}
|
||||
if nameIndex < 0 || int(nameIndex) >= len(gen.names) {
|
||||
return errors.New("nameIndex is out of range")
|
||||
}
|
||||
gen.addMapping(generatedLine, generatedCharacter, sourceIndex, sourceLine, sourceCharacter, nameIndex)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Gets the source map as a `RawSourceMap` object
|
||||
func (gen *Generator) RawSourceMap() *RawSourceMap {
|
||||
gen.commitPendingMapping()
|
||||
sources := slices.Clone(gen.sources)
|
||||
if sources == nil {
|
||||
sources = []string{}
|
||||
}
|
||||
names := slices.Clone(gen.names)
|
||||
if names == nil {
|
||||
names = []string{}
|
||||
}
|
||||
return &RawSourceMap{
|
||||
Version: 3,
|
||||
File: gen.file,
|
||||
SourceRoot: gen.sourceRoot,
|
||||
Sources: sources,
|
||||
Names: names,
|
||||
Mappings: gen.mappings.String(),
|
||||
SourcesContent: slices.Clone(gen.sourcesContent),
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the string representation of the source map
|
||||
func (gen *Generator) String() string {
|
||||
buf, err := json.Marshal(gen.RawSourceMap())
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
func base64FormatEncode(value int) rune {
|
||||
switch {
|
||||
case value >= 0 && value < 26:
|
||||
return 'A' + rune(value)
|
||||
case value >= 26 && value < 52:
|
||||
return 'a' + rune(value) - 26
|
||||
case value >= 52 && value < 62:
|
||||
return '0' + rune(value) - 52
|
||||
case value == 62:
|
||||
return '+'
|
||||
case value == 63:
|
||||
return '/'
|
||||
default:
|
||||
panic("not a base64 value")
|
||||
}
|
||||
}
|
||||
@ -1,383 +0,0 @@
|
||||
package sourcemap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestSourceMapGenerator_Empty(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{},
|
||||
Mappings: "",
|
||||
Names: []string{},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_Empty_Serialized(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
actual := gen.String()
|
||||
expected := `{"version":3,"file":"main.js","sourceRoot":"/","sources":[],"names":[],"mappings":""}`
|
||||
assert.Equal(t, actual, expected)
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSource(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.Equal(t, int(sourceIndex), 0)
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"main.ts"},
|
||||
Mappings: "",
|
||||
Names: []string{},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_SetSourceContent(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
sourceContent := "foo"
|
||||
assert.NilError(t, gen.SetSourceContent(sourceIndex, sourceContent))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.Equal(t, int(sourceIndex), 0)
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"main.ts"},
|
||||
Mappings: "",
|
||||
Names: []string{},
|
||||
SourcesContent: []*string{&sourceContent},
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_SetSourceContent_ForSecondSourceOnly(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
gen.AddSource("/skipped.ts")
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
sourceContent := "foo"
|
||||
assert.NilError(t, gen.SetSourceContent(sourceIndex, sourceContent))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.Equal(t, int(sourceIndex), 1)
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"skipped.ts", "main.ts"},
|
||||
Mappings: "",
|
||||
Names: []string{},
|
||||
SourcesContent: []*string{nil, &sourceContent},
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_SetSourceContent_SourceIndexOutOfRange(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
assert.Error(t, gen.SetSourceContent(-1, ""), "sourceIndex is out of range")
|
||||
assert.Error(t, gen.SetSourceContent(0, ""), "sourceIndex is out of range")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_SetSourceContent_ForSecondSourceOnly_Serialized(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
gen.AddSource("/skipped.ts")
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
sourceContent := "foo"
|
||||
assert.NilError(t, gen.SetSourceContent(sourceIndex, sourceContent))
|
||||
actual := gen.String()
|
||||
expected := `{"version":3,"file":"main.js","sourceRoot":"/","sources":["skipped.ts","main.ts"],"names":[],"mappings":"","sourcesContent":[null,"foo"]}`
|
||||
assert.Equal(t, actual, expected)
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddName(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
nameIndex := gen.AddName("foo")
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.Equal(t, int(nameIndex), 0)
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{},
|
||||
Mappings: "",
|
||||
Names: []string{"foo"},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddGeneratedMapping(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
assert.NilError(t, gen.AddGeneratedMapping(0, 0))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{},
|
||||
Mappings: "A",
|
||||
Names: []string{},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddGeneratedMapping_OnSecondLineOnly(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
assert.NilError(t, gen.AddGeneratedMapping(1, 0))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{},
|
||||
Mappings: ";A",
|
||||
Names: []string{},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.NilError(t, gen.AddSourceMapping(0, 0, sourceIndex, 0, 0))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"main.ts"},
|
||||
Mappings: "AAAA",
|
||||
Names: []string{},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping_NextGeneratedCharacter(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.NilError(t, gen.AddSourceMapping(0, 0, sourceIndex, 0, 0))
|
||||
assert.NilError(t, gen.AddSourceMapping(0, 1, sourceIndex, 0, 0))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"main.ts"},
|
||||
Mappings: "AAAA,CAAA",
|
||||
Names: []string{},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping_NextGeneratedAndSourceCharacter(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.NilError(t, gen.AddSourceMapping(0, 0, sourceIndex, 0, 0))
|
||||
assert.NilError(t, gen.AddSourceMapping(0, 1, sourceIndex, 0, 1))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"main.ts"},
|
||||
Mappings: "AAAA,CAAC",
|
||||
Names: []string{},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping_NextGeneratedLine(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.NilError(t, gen.AddSourceMapping(0, 0, sourceIndex, 0, 0))
|
||||
assert.NilError(t, gen.AddSourceMapping(1, 0, sourceIndex, 0, 0))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"main.ts"},
|
||||
Mappings: "AAAA;AAAA",
|
||||
Names: []string{},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping_PreviousSourceCharacter(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.NilError(t, gen.AddSourceMapping(0, 0, sourceIndex, 0, 1))
|
||||
assert.NilError(t, gen.AddSourceMapping(0, 1, sourceIndex, 0, 0))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"main.ts"},
|
||||
Mappings: "AAAC,CAAD",
|
||||
Names: []string{},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddNamedSourceMapping(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
nameIndex := gen.AddName("foo")
|
||||
assert.NilError(t, gen.AddNamedSourceMapping(0, 0, sourceIndex, 0, 0, nameIndex))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"main.ts"},
|
||||
Mappings: "AAAAA",
|
||||
Names: []string{"foo"},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddNamedSourceMapping_WithPreviousName(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
nameIndex1 := gen.AddName("foo")
|
||||
nameIndex2 := gen.AddName("bar")
|
||||
assert.NilError(t, gen.AddNamedSourceMapping(0, 0, sourceIndex, 0, 0, nameIndex2))
|
||||
assert.NilError(t, gen.AddNamedSourceMapping(0, 1, sourceIndex, 0, 0, nameIndex1))
|
||||
sourceMap := gen.RawSourceMap()
|
||||
assert.DeepEqual(t, sourceMap, &RawSourceMap{
|
||||
Version: 3,
|
||||
File: "main.js",
|
||||
SourceRoot: "/",
|
||||
Sources: []string{"main.ts"},
|
||||
Mappings: "AAAAC,CAAAD",
|
||||
Names: []string{"foo", "bar"},
|
||||
SourcesContent: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddGeneratedMapping_GeneratedLineCannotBacktrack(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
assert.NilError(t, gen.AddGeneratedMapping(1, 0))
|
||||
assert.Error(t, gen.AddGeneratedMapping(0, 0), "generatedLine cannot backtrack")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddGeneratedMapping_GeneratedCharacterCannotBeNegative(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
assert.NilError(t, gen.AddGeneratedMapping(0, 0))
|
||||
assert.Error(t, gen.AddGeneratedMapping(0, -1), "generatedCharacter cannot be negative")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping_GeneratedLineCannotBacktrack(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.NilError(t, gen.AddSourceMapping(1, 0, sourceIndex, 0, 0))
|
||||
assert.Error(t, gen.AddSourceMapping(0, 0, sourceIndex, 0, 0), "generatedLine cannot backtrack")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping_GeneratedCharacterCannotBeNegative(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.NilError(t, gen.AddSourceMapping(0, 0, sourceIndex, 0, 0))
|
||||
assert.Error(t, gen.AddSourceMapping(0, -1, sourceIndex, 0, 0), "generatedCharacter cannot be negative")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping_SourceIndexIsOutOfRange(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
assert.Error(t, gen.AddSourceMapping(0, 0, -1, 0, 0), "sourceIndex is out of range")
|
||||
assert.Error(t, gen.AddSourceMapping(0, 0, 0, 0, 0), "sourceIndex is out of range")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping_SourceLineCannotBeNegative(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.Error(t, gen.AddSourceMapping(0, 0, sourceIndex, -1, 0), "sourceLine cannot be negative")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddSourceMapping_SourceCharacterCannotBeNegative(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.Error(t, gen.AddSourceMapping(0, 0, sourceIndex, 0, -1), "sourceCharacter cannot be negative")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddNamedSourceMapping_GeneratedLineCannotBacktrack(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
nameIndex := gen.AddName("foo")
|
||||
assert.NilError(t, gen.AddNamedSourceMapping(1, 0, sourceIndex, 0, 0, nameIndex))
|
||||
assert.Error(t, gen.AddNamedSourceMapping(0, 0, sourceIndex, 0, 0, nameIndex), "generatedLine cannot backtrack")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddNamedSourceMapping_GeneratedCharacterCannotBeNegative(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
nameIndex := gen.AddName("foo")
|
||||
assert.NilError(t, gen.AddNamedSourceMapping(0, 0, sourceIndex, 0, 0, nameIndex))
|
||||
assert.Error(t, gen.AddNamedSourceMapping(0, -1, sourceIndex, 0, 0, nameIndex), "generatedCharacter cannot be negative")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddNamedSourceMapping_SourceIndexIsOutOfRange(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
nameIndex := gen.AddName("foo")
|
||||
assert.Error(t, gen.AddNamedSourceMapping(0, 0, -1, 0, 0, nameIndex), "sourceIndex is out of range")
|
||||
assert.Error(t, gen.AddNamedSourceMapping(0, 0, 0, 0, 0, nameIndex), "sourceIndex is out of range")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddNamedSourceMapping_SourceLineCannotBeNegative(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
nameIndex := gen.AddName("foo")
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.Error(t, gen.AddNamedSourceMapping(0, 0, sourceIndex, -1, 0, nameIndex), "sourceLine cannot be negative")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddNamedSourceMapping_SourceCharacterCannotBeNegative(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
nameIndex := gen.AddName("foo")
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.Error(t, gen.AddNamedSourceMapping(0, 0, sourceIndex, 0, -1, nameIndex), "sourceCharacter cannot be negative")
|
||||
}
|
||||
|
||||
func TestSourceMapGenerator_AddNamedSourceMapping_NameIndexIsOutOfRange(t *testing.T) {
|
||||
t.Parallel()
|
||||
gen := NewGenerator("main.js", "/", "/", tspath.ComparePathsOptions{})
|
||||
sourceIndex := gen.AddSource("/main.ts")
|
||||
assert.Error(t, gen.AddNamedSourceMapping(0, 0, sourceIndex, 0, 0, -1), "nameIndex is out of range")
|
||||
assert.Error(t, gen.AddNamedSourceMapping(0, 0, sourceIndex, 0, 0, 0), "nameIndex is out of range")
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package sourcemap
|
||||
|
||||
import "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
|
||||
type ECMALineInfo struct {
|
||||
text string
|
||||
lineStarts core.ECMALineStarts
|
||||
}
|
||||
|
||||
func CreateECMALineInfo(text string, lineStarts core.ECMALineStarts) *ECMALineInfo {
|
||||
return &ECMALineInfo{
|
||||
text: text,
|
||||
lineStarts: lineStarts,
|
||||
}
|
||||
}
|
||||
|
||||
func (li *ECMALineInfo) LineCount() int {
|
||||
return len(li.lineStarts)
|
||||
}
|
||||
|
||||
func (li *ECMALineInfo) LineText(line int) string {
|
||||
pos := li.lineStarts[line]
|
||||
var end core.TextPos
|
||||
if line+1 < len(li.lineStarts) {
|
||||
end = li.lineStarts[line+1]
|
||||
} else {
|
||||
end = core.TextPos(len(li.text))
|
||||
}
|
||||
return li.text[pos:end]
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package sourcemap
|
||||
|
||||
import "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
|
||||
type Source interface {
|
||||
Text() string
|
||||
FileName() string
|
||||
ECMALineMap() []core.TextPos
|
||||
}
|
||||
@ -1,313 +0,0 @@
|
||||
package sourcemap
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/debug"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/stringutil"
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
||||
"github.com/go-json-experiment/json"
|
||||
)
|
||||
|
||||
type Host interface {
|
||||
UseCaseSensitiveFileNames() bool
|
||||
GetECMALineInfo(fileName string) *ECMALineInfo
|
||||
ReadFile(fileName string) (string, bool)
|
||||
}
|
||||
|
||||
// Similar to `Mapping`, but position-based.
|
||||
type MappedPosition struct {
|
||||
generatedPosition int
|
||||
sourcePosition int
|
||||
sourceIndex SourceIndex
|
||||
nameIndex NameIndex
|
||||
}
|
||||
|
||||
const (
|
||||
missingPosition = -1
|
||||
)
|
||||
|
||||
func (m *MappedPosition) isSourceMappedPosition() bool {
|
||||
return m.sourceIndex != MissingSource && m.sourcePosition != missingPosition
|
||||
}
|
||||
|
||||
type SourceMappedPosition = MappedPosition
|
||||
|
||||
// Maps source positions to generated positions and vice versa.
|
||||
type DocumentPositionMapper struct {
|
||||
useCaseSensitiveFileNames bool
|
||||
|
||||
sourceFileAbsolutePaths []string
|
||||
sourceToSourceIndexMap map[string]SourceIndex
|
||||
generatedAbsoluteFilePath string
|
||||
|
||||
generatedMappings []*MappedPosition
|
||||
sourceMappings map[SourceIndex][]*SourceMappedPosition
|
||||
}
|
||||
|
||||
func createDocumentPositionMapper(host Host, sourceMap *RawSourceMap, mapPath string) *DocumentPositionMapper {
|
||||
mapDirectory := tspath.GetDirectoryPath(mapPath)
|
||||
var sourceRoot string
|
||||
if sourceMap.SourceRoot != "" {
|
||||
sourceRoot = tspath.GetNormalizedAbsolutePath(sourceMap.SourceRoot, mapDirectory)
|
||||
} else {
|
||||
sourceRoot = mapDirectory
|
||||
}
|
||||
generatedAbsoluteFilePath := tspath.GetNormalizedAbsolutePath(sourceMap.File, mapDirectory)
|
||||
sourceFileAbsolutePaths := core.Map(sourceMap.Sources, func(source string) string {
|
||||
return tspath.GetNormalizedAbsolutePath(source, sourceRoot)
|
||||
})
|
||||
useCaseSensitiveFileNames := host.UseCaseSensitiveFileNames()
|
||||
sourceToSourceIndexMap := make(map[string]SourceIndex, len(sourceFileAbsolutePaths))
|
||||
for i, source := range sourceFileAbsolutePaths {
|
||||
sourceToSourceIndexMap[tspath.GetCanonicalFileName(source, useCaseSensitiveFileNames)] = SourceIndex(i)
|
||||
}
|
||||
|
||||
var decodedMappings []*MappedPosition
|
||||
var generatedMappings []*MappedPosition
|
||||
sourceMappings := make(map[SourceIndex][]*SourceMappedPosition)
|
||||
|
||||
// getDecodedMappings()
|
||||
decoder := DecodeMappings(sourceMap.Mappings)
|
||||
for mapping := range decoder.Values() {
|
||||
// processMapping()
|
||||
generatedPosition := -1
|
||||
lineInfo := host.GetECMALineInfo(generatedAbsoluteFilePath)
|
||||
if lineInfo != nil {
|
||||
generatedPosition = scanner.ComputePositionOfLineAndCharacterEx(
|
||||
lineInfo.lineStarts,
|
||||
mapping.GeneratedLine,
|
||||
mapping.GeneratedCharacter,
|
||||
&lineInfo.text,
|
||||
true, /*allowEdits*/
|
||||
)
|
||||
}
|
||||
|
||||
sourcePosition := -1
|
||||
if mapping.IsSourceMapping() {
|
||||
lineInfo := host.GetECMALineInfo(sourceFileAbsolutePaths[mapping.SourceIndex])
|
||||
if lineInfo != nil {
|
||||
pos := scanner.ComputePositionOfLineAndCharacterEx(
|
||||
lineInfo.lineStarts,
|
||||
mapping.SourceLine,
|
||||
mapping.SourceCharacter,
|
||||
&lineInfo.text,
|
||||
true, /*allowEdits*/
|
||||
)
|
||||
sourcePosition = pos
|
||||
}
|
||||
}
|
||||
|
||||
decodedMappings = append(decodedMappings, &MappedPosition{
|
||||
generatedPosition: generatedPosition,
|
||||
sourceIndex: mapping.SourceIndex,
|
||||
sourcePosition: sourcePosition,
|
||||
nameIndex: mapping.NameIndex,
|
||||
})
|
||||
}
|
||||
if decoder.Error() != nil {
|
||||
decodedMappings = nil
|
||||
}
|
||||
|
||||
// getSourceMappings()
|
||||
for _, mapping := range decodedMappings {
|
||||
if !mapping.isSourceMappedPosition() {
|
||||
continue
|
||||
}
|
||||
sourceIndex := mapping.sourceIndex
|
||||
list := sourceMappings[sourceIndex]
|
||||
list = append(list, &SourceMappedPosition{
|
||||
generatedPosition: mapping.generatedPosition,
|
||||
sourceIndex: sourceIndex,
|
||||
sourcePosition: mapping.sourcePosition,
|
||||
nameIndex: mapping.nameIndex,
|
||||
})
|
||||
sourceMappings[sourceIndex] = list
|
||||
}
|
||||
for i, list := range sourceMappings {
|
||||
slices.SortFunc(list, func(a, b *SourceMappedPosition) int {
|
||||
debug.Assert(a.sourceIndex == b.sourceIndex, "All source mappings should have the same source index")
|
||||
return a.sourcePosition - b.sourcePosition
|
||||
})
|
||||
sourceMappings[i] = core.DeduplicateSorted(list, func(a, b *SourceMappedPosition) bool {
|
||||
return a.generatedPosition == b.generatedPosition &&
|
||||
a.sourceIndex == b.sourceIndex &&
|
||||
a.sourcePosition == b.sourcePosition
|
||||
})
|
||||
}
|
||||
|
||||
// getGeneratedMappings()
|
||||
generatedMappings = decodedMappings
|
||||
slices.SortFunc(generatedMappings, func(a, b *MappedPosition) int {
|
||||
return a.generatedPosition - b.generatedPosition
|
||||
})
|
||||
generatedMappings = core.DeduplicateSorted(generatedMappings, func(a, b *MappedPosition) bool {
|
||||
return a.generatedPosition == b.generatedPosition &&
|
||||
a.sourceIndex == b.sourceIndex &&
|
||||
a.sourcePosition == b.sourcePosition
|
||||
})
|
||||
|
||||
return &DocumentPositionMapper{
|
||||
useCaseSensitiveFileNames: useCaseSensitiveFileNames,
|
||||
sourceFileAbsolutePaths: sourceFileAbsolutePaths,
|
||||
sourceToSourceIndexMap: sourceToSourceIndexMap,
|
||||
generatedAbsoluteFilePath: generatedAbsoluteFilePath,
|
||||
generatedMappings: generatedMappings,
|
||||
sourceMappings: sourceMappings,
|
||||
}
|
||||
}
|
||||
|
||||
type DocumentPosition struct {
|
||||
FileName string
|
||||
Pos int
|
||||
}
|
||||
|
||||
func (d *DocumentPositionMapper) GetSourcePosition(loc *DocumentPosition) *DocumentPosition {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
if len(d.generatedMappings) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
targetIndex, _ := slices.BinarySearchFunc(d.generatedMappings, loc.Pos, func(m *MappedPosition, pos int) int {
|
||||
return m.generatedPosition - pos
|
||||
})
|
||||
|
||||
if targetIndex < 0 || targetIndex >= len(d.generatedMappings) {
|
||||
return nil
|
||||
}
|
||||
|
||||
mapping := d.generatedMappings[targetIndex]
|
||||
if !mapping.isSourceMappedPosition() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Closest position
|
||||
return &DocumentPosition{
|
||||
FileName: d.sourceFileAbsolutePaths[mapping.sourceIndex],
|
||||
Pos: mapping.sourcePosition,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DocumentPositionMapper) GetGeneratedPosition(loc *DocumentPosition) *DocumentPosition {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
sourceIndex, ok := d.sourceToSourceIndexMap[tspath.GetCanonicalFileName(loc.FileName, d.useCaseSensitiveFileNames)]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if sourceIndex < 0 || int(sourceIndex) >= len(d.sourceMappings) {
|
||||
return nil
|
||||
}
|
||||
sourceMappings := d.sourceMappings[sourceIndex]
|
||||
targetIndex, _ := slices.BinarySearchFunc(sourceMappings, loc.Pos, func(m *SourceMappedPosition, pos int) int {
|
||||
return m.sourcePosition - pos
|
||||
})
|
||||
|
||||
if targetIndex < 0 || targetIndex >= len(sourceMappings) {
|
||||
return nil
|
||||
}
|
||||
|
||||
mapping := sourceMappings[targetIndex]
|
||||
if mapping.sourceIndex != sourceIndex {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Closest position
|
||||
return &DocumentPosition{
|
||||
FileName: d.generatedAbsoluteFilePath,
|
||||
Pos: mapping.generatedPosition,
|
||||
}
|
||||
}
|
||||
|
||||
func GetDocumentPositionMapper(host Host, generatedFileName string) *DocumentPositionMapper {
|
||||
mapFileName := tryGetSourceMappingURL(host, generatedFileName)
|
||||
if mapFileName != "" {
|
||||
if base64Object, matched := tryParseBase64Url(mapFileName); matched {
|
||||
if base64Object != "" {
|
||||
if decoded, err := base64.StdEncoding.DecodeString(base64Object); err == nil {
|
||||
return convertDocumentToSourceMapper(host, string(decoded), generatedFileName)
|
||||
}
|
||||
}
|
||||
// Not a data URL we can parse, skip it
|
||||
mapFileName = ""
|
||||
}
|
||||
}
|
||||
|
||||
var possibleMapLocations []string
|
||||
if mapFileName != "" {
|
||||
possibleMapLocations = append(possibleMapLocations, mapFileName)
|
||||
}
|
||||
possibleMapLocations = append(possibleMapLocations, generatedFileName+".map")
|
||||
for _, location := range possibleMapLocations {
|
||||
mapFileName := tspath.GetNormalizedAbsolutePath(location, tspath.GetDirectoryPath(generatedFileName))
|
||||
if mapFileContents, ok := host.ReadFile(mapFileName); ok {
|
||||
return convertDocumentToSourceMapper(host, mapFileContents, mapFileName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertDocumentToSourceMapper(host Host, contents string, mapFileName string) *DocumentPositionMapper {
|
||||
sourceMap := tryParseRawSourceMap(contents)
|
||||
if sourceMap == nil || len(sourceMap.Sources) == 0 || sourceMap.File == "" || sourceMap.Mappings == "" {
|
||||
// invalid map
|
||||
return nil
|
||||
}
|
||||
|
||||
// Don't support source maps that contain inlined sources
|
||||
if core.Some(sourceMap.SourcesContent, func(s *string) bool { return s != nil }) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return createDocumentPositionMapper(host, sourceMap, mapFileName)
|
||||
}
|
||||
|
||||
func tryParseRawSourceMap(contents string) *RawSourceMap {
|
||||
sourceMap := &RawSourceMap{}
|
||||
err := json.Unmarshal([]byte(contents), sourceMap)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if sourceMap.Version != 3 {
|
||||
return nil
|
||||
}
|
||||
return sourceMap
|
||||
}
|
||||
|
||||
func tryGetSourceMappingURL(host Host, fileName string) string {
|
||||
lineInfo := host.GetECMALineInfo(fileName)
|
||||
return TryGetSourceMappingURL(lineInfo)
|
||||
}
|
||||
|
||||
// Equivalent to /^data:(?:application\/json;(?:charset=[uU][tT][fF]-8;)?base64,([A-Za-z0-9+/=]+)$)?/
|
||||
func tryParseBase64Url(url string) (parseableUrl string, isBase64Url bool) {
|
||||
var found bool
|
||||
if url, found = strings.CutPrefix(url, `data:`); !found {
|
||||
return "", false
|
||||
}
|
||||
if url, found = strings.CutPrefix(url, `application/json;`); !found {
|
||||
return "", true
|
||||
}
|
||||
if url, found = strings.CutPrefix(url, `charset=`); found {
|
||||
if !strings.EqualFold(url[:len(`utf-8;`)], `utf-8;`) {
|
||||
return "", true
|
||||
}
|
||||
url = url[len(`utf-8;`):]
|
||||
}
|
||||
if url, found = strings.CutPrefix(url, `base64,`); !found {
|
||||
return "", true
|
||||
}
|
||||
for _, r := range url {
|
||||
if !(stringutil.IsASCIILetter(r) || stringutil.IsDigit(r) || r == '+' || r == '/' || r == '=') {
|
||||
return "", true
|
||||
}
|
||||
}
|
||||
return url, true
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
package sourcemap
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/stringutil"
|
||||
)
|
||||
|
||||
// Tries to find the sourceMappingURL comment at the end of a file.
|
||||
func TryGetSourceMappingURL(lineInfo *ECMALineInfo) string {
|
||||
for index := lineInfo.LineCount() - 1; index >= 0; index-- {
|
||||
line := lineInfo.LineText(index)
|
||||
line = strings.TrimLeftFunc(line, unicode.IsSpace)
|
||||
line = strings.TrimRightFunc(line, stringutil.IsLineBreak)
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(line) < 4 || !strings.HasPrefix(line, "//") || line[2] != '#' && line[2] != '@' || line[3] != ' ' {
|
||||
break
|
||||
}
|
||||
if url, ok := strings.CutPrefix(line[4:], "sourceMappingURL="); ok {
|
||||
return strings.TrimRightFunc(url, unicode.IsSpace)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user