github.com/vanstinator/golangci-lint@v0.0.0-20240223191551-cc572f00d9d1/pkg/printers/html.go (about) 1 package printers 2 3 import ( 4 "fmt" 5 "html/template" 6 "io" 7 "strings" 8 9 "github.com/vanstinator/golangci-lint/pkg/result" 10 ) 11 12 const templateContent = `<!doctype html> 13 <html lang="en"> 14 <head> 15 <meta charset="utf-8"> 16 <title>golangci-lint</title> 17 <link rel="shortcut icon" type="image/png" href="https://golangci-lint.run/favicon-32x32.png"> 18 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.2/css/bulma.min.css" 19 integrity="sha512-byErQdWdTqREz6DLAA9pCnLbdoGGhXfU6gm1c8bkf7F51JVmUBlayGe2A31VpXWQP+eiJ3ilTAZHCR3vmMyybA==" 20 crossorigin="anonymous" referrerpolicy="no-referrer"/> 21 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/default.min.css" 22 integrity="sha512-kZqGbhf9JTB4bVJ0G8HCkqmaPcRgo88F0dneK30yku5Y/dep7CZfCnNml2Je/sY4lBoqoksXz4PtVXS4GHSUzQ==" 23 crossorigin="anonymous" referrerpolicy="no-referrer"/> 24 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js" 25 integrity="sha512-s+tOYYcC3Jybgr9mVsdAxsRYlGNq4mlAurOrfNuGMQ/SCofNPu92tjE7YRZCsdEtWL1yGkqk15fU/ark206YTg==" 26 crossorigin="anonymous" referrerpolicy="no-referrer"></script> 27 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/languages/go.min.js" 28 integrity="sha512-+UYV2NyyynWEQcZ4sMTKmeppyV331gqvMOGZ61/dqc89Tn1H40lF05ACd03RSD9EWwGutNwKj256mIR8waEJBQ==" 29 crossorigin="anonymous" referrerpolicy="no-referrer"></script> 30 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js" 31 integrity="sha512-qlzIeUtTg7eBpmEaS12NZgxz52YYZVF5myj89mjJEesBd/oE9UPsYOX2QAXzvOAZYEvQohKdcY8zKE02ifXDmA==" 32 crossorigin="anonymous" referrerpolicy="no-referrer"></script> 33 <script type="text/javascript" 34 src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js" 35 integrity="sha512-9jGNr5Piwe8nzLLYTk8QrEMPfjGU0px80GYzKZUxi7lmCfrBjtyCc1V5kkS5vxVwwIB7Qpzc7UxLiQxfAN30dw==" 36 crossorigin="anonymous" referrerpolicy="no-referrer"></script> 37 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js" 38 integrity="sha512-kp7YHLxuJDJcOzStgd6vtpxr4ZU9kjn77e6dBsivSz+pUuAuMlE2UTdKB7jjsWT84qbS8kdCWHPETnP/ctrFsA==" 39 crossorigin="anonymous" referrerpolicy="no-referrer"></script> 40 </head> 41 <body> 42 <section class="section"> 43 <div class="container"> 44 <div id="content"></div> 45 </div> 46 </section> 47 <script> 48 const data = {{ . }}; 49 </script> 50 <script type="text/babel"> 51 class Highlight extends React.Component { 52 componentDidMount() { 53 hljs.highlightElement(ReactDOM.findDOMNode(this)); 54 } 55 56 render() { 57 return <pre className="go"><code>{this.props.code}</code></pre>; 58 } 59 } 60 61 class Issue extends React.Component { 62 render() { 63 return ( 64 <div className="issue box"> 65 <div> 66 <div className="columns"> 67 <div className="column is-four-fifths"> 68 <h5 className="title is-5 has-text-danger-dark">{this.props.data.Title}</h5> 69 </div> 70 <div className="column is-one-fifth"> 71 <h6 className="title is-6">{this.props.data.Linter}</h6> 72 </div> 73 </div> 74 <strong>{this.props.data.Pos}</strong> 75 </div> 76 <div className="highlight"> 77 <Highlight code={this.props.data.Code}/> 78 </div> 79 </div> 80 ); 81 } 82 } 83 84 class Issues extends React.Component { 85 render() { 86 if (!this.props.data.Issues || this.props.data.Issues.length === 0) { 87 return ( 88 <div> 89 <div className="notification"> 90 No issues found! 91 </div> 92 </div> 93 ); 94 } 95 96 return ( 97 <div className="issues"> 98 {this.props.data.Issues.map(issue => (<Issue data={issue}/>))} 99 </div> 100 ); 101 } 102 } 103 104 ReactDOM.render( 105 <div className="content"> 106 <div className="columns is-centered"> 107 <div className="column is-three-quarters"> 108 <Issues data={data}/> 109 </div> 110 </div> 111 </div>, 112 document.getElementById("content") 113 ); 114 </script> 115 </body> 116 </html>` 117 118 type htmlIssue struct { 119 Title string 120 Pos string 121 Linter string 122 Code string 123 } 124 125 type HTML struct { 126 w io.Writer 127 } 128 129 func NewHTML(w io.Writer) *HTML { 130 return &HTML{w: w} 131 } 132 133 func (p HTML) Print(issues []result.Issue) error { 134 var htmlIssues []htmlIssue 135 136 for i := range issues { 137 pos := fmt.Sprintf("%s:%d", issues[i].FilePath(), issues[i].Line()) 138 if issues[i].Pos.Column != 0 { 139 pos += fmt.Sprintf(":%d", issues[i].Pos.Column) 140 } 141 142 htmlIssues = append(htmlIssues, htmlIssue{ 143 Title: strings.TrimSpace(issues[i].Text), 144 Pos: pos, 145 Linter: issues[i].FromLinter, 146 Code: strings.Join(issues[i].SourceLines, "\n"), 147 }) 148 } 149 150 t, err := template.New("golangci-lint").Parse(templateContent) 151 if err != nil { 152 return err 153 } 154 155 return t.Execute(p.w, struct{ Issues []htmlIssue }{Issues: htmlIssues}) 156 }