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 }