github.com/evanw/esbuild@v0.21.4/internal/linker/debug.go (about)

     1  package linker
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/evanw/esbuild/internal/ast"
     8  	"github.com/evanw/esbuild/internal/graph"
     9  	"github.com/evanw/esbuild/internal/helpers"
    10  	"github.com/evanw/esbuild/internal/js_ast"
    11  )
    12  
    13  // Set this to true and then load the resulting metafile in "graph-debugger.html"
    14  // to debug graph information.
    15  //
    16  // This is deliberately not exposed in the final binary. It is *very* internal
    17  // and only exists to help debug esbuild itself. Make sure this is always set
    18  // back to false before committing.
    19  const debugVerboseMetafile = false
    20  
    21  func (c *linkerContext) generateExtraDataForFileJS(sourceIndex uint32) string {
    22  	if !debugVerboseMetafile {
    23  		return ""
    24  	}
    25  
    26  	file := &c.graph.Files[sourceIndex]
    27  	repr := file.InputFile.Repr.(*graph.JSRepr)
    28  	sb := strings.Builder{}
    29  	isFirstPartWithStmts := true
    30  
    31  	quoteSym := func(ref ast.Ref) string {
    32  		name := fmt.Sprintf("%d:%d [%s]", ref.SourceIndex, ref.InnerIndex, c.graph.Symbols.Get(ref).OriginalName)
    33  		return string(helpers.QuoteForJSON(name, c.options.ASCIIOnly))
    34  	}
    35  
    36  	sb.WriteString(`,"parts":[`)
    37  	for partIndex, part := range repr.AST.Parts {
    38  		if partIndex > 0 {
    39  			sb.WriteByte(',')
    40  		}
    41  		var isFirst bool
    42  		code := ""
    43  
    44  		sb.WriteString(fmt.Sprintf(`{"isLive":%v`, part.IsLive))
    45  		sb.WriteString(fmt.Sprintf(`,"canBeRemovedIfUnused":%v`, part.CanBeRemovedIfUnused))
    46  
    47  		if partIndex == int(js_ast.NSExportPartIndex) {
    48  			sb.WriteString(`,"nsExportPartIndex":true`)
    49  		} else if ast.MakeIndex32(uint32(partIndex)) == repr.Meta.WrapperPartIndex {
    50  			sb.WriteString(`,"wrapperPartIndex":true`)
    51  		} else if len(part.Stmts) > 0 {
    52  			contents := file.InputFile.Source.Contents
    53  			start := int(part.Stmts[0].Loc.Start)
    54  			if isFirstPartWithStmts {
    55  				start = 0
    56  				isFirstPartWithStmts = false
    57  			}
    58  			end := len(contents)
    59  			if partIndex+1 < len(repr.AST.Parts) {
    60  				if nextStmts := repr.AST.Parts[partIndex+1].Stmts; len(nextStmts) > 0 {
    61  					if nextStart := int(nextStmts[0].Loc.Start); nextStart >= start {
    62  						end = int(nextStart)
    63  					}
    64  				}
    65  			}
    66  			start = moveBeforeExport(contents, start)
    67  			end = moveBeforeExport(contents, end)
    68  			code = contents[start:end]
    69  		}
    70  
    71  		// importRecords
    72  		sb.WriteString(`,"importRecords":[`)
    73  		isFirst = true
    74  		for _, importRecordIndex := range part.ImportRecordIndices {
    75  			record := repr.AST.ImportRecords[importRecordIndex]
    76  			if !record.SourceIndex.IsValid() {
    77  				continue
    78  			}
    79  			if isFirst {
    80  				isFirst = false
    81  			} else {
    82  				sb.WriteByte(',')
    83  			}
    84  			path := c.graph.Files[record.SourceIndex.GetIndex()].InputFile.Source.PrettyPath
    85  			sb.WriteString(fmt.Sprintf(`{"source":%s}`, helpers.QuoteForJSON(path, c.options.ASCIIOnly)))
    86  		}
    87  		sb.WriteByte(']')
    88  
    89  		// declaredSymbols
    90  		sb.WriteString(`,"declaredSymbols":[`)
    91  		isFirst = true
    92  		for _, declSym := range part.DeclaredSymbols {
    93  			if !declSym.IsTopLevel {
    94  				continue
    95  			}
    96  			if isFirst {
    97  				isFirst = false
    98  			} else {
    99  				sb.WriteByte(',')
   100  			}
   101  			sb.WriteString(fmt.Sprintf(`{"name":%s}`, quoteSym(declSym.Ref)))
   102  		}
   103  		sb.WriteByte(']')
   104  
   105  		// symbolUses
   106  		sb.WriteString(`,"symbolUses":[`)
   107  		isFirst = true
   108  		for ref, uses := range part.SymbolUses {
   109  			if isFirst {
   110  				isFirst = false
   111  			} else {
   112  				sb.WriteByte(',')
   113  			}
   114  			sb.WriteString(fmt.Sprintf(`{"name":%s,"countEstimate":%d}`, quoteSym(ref), uses.CountEstimate))
   115  		}
   116  		sb.WriteByte(']')
   117  
   118  		// dependencies
   119  		sb.WriteString(`,"dependencies":[`)
   120  		for i, dep := range part.Dependencies {
   121  			if i > 0 {
   122  				sb.WriteByte(',')
   123  			}
   124  			sb.WriteString(fmt.Sprintf(`{"source":%s,"partIndex":%d}`,
   125  				helpers.QuoteForJSON(c.graph.Files[dep.SourceIndex].InputFile.Source.PrettyPath, c.options.ASCIIOnly),
   126  				dep.PartIndex,
   127  			))
   128  		}
   129  		sb.WriteByte(']')
   130  
   131  		// code
   132  		sb.WriteString(`,"code":`)
   133  		sb.Write(helpers.QuoteForJSON(code, c.options.ASCIIOnly))
   134  
   135  		sb.WriteByte('}')
   136  	}
   137  	sb.WriteString(`]`)
   138  
   139  	return sb.String()
   140  }
   141  
   142  func moveBeforeExport(contents string, i int) int {
   143  	contents = strings.TrimRight(contents[:i], " \t\r\n")
   144  	if strings.HasSuffix(contents, "export") {
   145  		return len(contents) - 6
   146  	}
   147  	return i
   148  }