github.com/nozzle/golangci-lint@v1.49.0-nz3/pkg/printers/html.go (about)

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