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