Skip to content

Commit ea004bd

Browse files
committed
html templates chapter
1 parent 8281d61 commit ea004bd

15 files changed

+1281
-33
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ I am proud to offer this resource for free, but if you wish to give some appreci
5858
14. [Intro to property based tests](roman-numerals.md) - Practice some TDD with the Roman Numerals kata and get a brief intro to property based tests
5959
15. [Maths](math.md) - Use the `math` package to draw an SVG clock
6060
16. [Reading files](reading-files.md) - Read files and process them
61+
17. [Templating](html-templates.md) - Use Go's html/template package to render html from data, and also learn about approval testing
6162

6263
### Build an application
6364

SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* [Intro to property based tests](roman-numerals.md)
2323
* [Maths](math.md)
2424
* [Reading files](reading-files.md)
25+
* [Templating](html-templates.md)
2526

2627
## Build an application
2728

blogrenderer/post.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package blogrenderer
2+
3+
import "strings"
4+
5+
// Post is a representation of a post
6+
type Post struct {
7+
Title, Description, Body string
8+
Tags []string
9+
}
10+
11+
// SanitisedTitle returns the title of the post with spaces replaced by dashes for pleasant URLs
12+
func (p Post) SanitisedTitle() string {
13+
return strings.ToLower(strings.Replace(p.Title, " ", "-", -1))
14+
}

blogrenderer/renderer.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package blogrenderer
2+
3+
import (
4+
"embed"
5+
"github.com/gomarkdown/markdown"
6+
"github.com/gomarkdown/markdown/parser"
7+
"html/template"
8+
"io"
9+
)
10+
11+
var (
12+
//go:embed "templates/*"
13+
postTemplates embed.FS
14+
)
15+
16+
// PostRenderer renders data into HTML
17+
type PostRenderer struct {
18+
templ *template.Template
19+
mdParser *parser.Parser
20+
}
21+
22+
// NewPostRenderer creates a new PostRenderer
23+
func NewPostRenderer() (*PostRenderer, error) {
24+
templ, err := template.ParseFS(postTemplates, "templates/*.gohtml")
25+
if err != nil {
26+
return nil, err
27+
}
28+
29+
extensions := parser.CommonExtensions | parser.AutoHeadingIDs
30+
parser := parser.NewWithExtensions(extensions)
31+
32+
return &PostRenderer{templ: templ, mdParser: parser}, nil
33+
}
34+
35+
// Render renders post into HTML
36+
func (r *PostRenderer) Render(w io.Writer, p Post) error {
37+
return r.templ.ExecuteTemplate(w, "blog.gohtml", newPostVM(p, r))
38+
}
39+
40+
// RenderIndex creates an HTML index page given a collection of posts
41+
func (r *PostRenderer) RenderIndex(w io.Writer, posts []Post) error {
42+
return r.templ.ExecuteTemplate(w, "index.gohtml", posts)
43+
}
44+
45+
type postViewModel struct {
46+
Post
47+
HTMLBody template.HTML
48+
}
49+
50+
func newPostVM(p Post, r *PostRenderer) postViewModel {
51+
vm := postViewModel{Post: p}
52+
vm.HTMLBody = template.HTML(markdown.ToHTML([]byte(p.Body), r.mdParser, nil))
53+
return vm
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>My amazing blog!</title>
5+
<meta charset="UTF-8"/>
6+
<meta name="description" content="Wow, like and subscribe, it really helps the channel guys" lang="en"/>
7+
</head>
8+
<body>
9+
<nav role="navigation">
10+
<div>
11+
<h1>Budding Gopher's blog</h1>
12+
<ul>
13+
<li><a href="/">home</a></li>
14+
<li><a href="about">about</a></li>
15+
<li><a href="archive">archive</a></li>
16+
</ul>
17+
</div>
18+
</nav>
19+
<main>
20+
21+
<h1>hello world</h1>
22+
23+
<p>This is a description</p>
24+
25+
Tags: <ul><li>go</li><li>tdd</li></ul>
26+
<h1 id="first-recipe">First recipe!</h1>
27+
28+
<p>Welcome to my <strong>amazing blog</strong>. I am going to write about my family recipes, and make sure I write a long, irrelevant and boring story about my family before you get to the actual instructions.</p>
29+
30+
31+
</main>
32+
<footer>
33+
<ul>
34+
<li><a href="https://twitter.com/quii">Twitter</a></li>
35+
<li><a href="https://github.com/quii">GitHub</a></li>
36+
</ul>
37+
</footer>
38+
</body>
39+
</html>
40+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>My amazing blog!</title>
5+
<meta charset="UTF-8"/>
6+
<meta name="description" content="Wow, like and subscribe, it really helps the channel guys" lang="en"/>
7+
</head>
8+
<body>
9+
<nav role="navigation">
10+
<div>
11+
<h1>Budding Gopher's blog</h1>
12+
<ul>
13+
<li><a href="/">home</a></li>
14+
<li><a href="about">about</a></li>
15+
<li><a href="archive">archive</a></li>
16+
</ul>
17+
</div>
18+
</nav>
19+
<main>
20+
21+
<ol><li><a href="/post/hello-world">Hello World</a></li><li><a href="/post/hello-world-2">Hello World 2</a></li></ol>
22+
23+
</main>
24+
<footer>
25+
<ul>
26+
<li><a href="https://twitter.com/quii">Twitter</a></li>
27+
<li><a href="https://github.com/quii">GitHub</a></li>
28+
</ul>
29+
</footer>
30+
</body>
31+
</html>
32+

blogrenderer/renderer_test.go

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package blogrenderer_test
2+
3+
import (
4+
"bytes"
5+
approvals "github.com/approvals/go-approval-tests"
6+
"github.com/quii/learn-go-with-tests/blogrenderer"
7+
"io"
8+
"testing"
9+
)
10+
11+
func TestRender(t *testing.T) {
12+
var (
13+
aPost = blogrenderer.Post{
14+
Title: "hello world",
15+
Body: `# First recipe!
16+
Welcome to my **amazing blog**. I am going to write about my family recipes, and make sure I write a long, irrelevant and boring story about my family before you get to the actual instructions.`,
17+
Description: "This is a description",
18+
Tags: []string{"go", "tdd"},
19+
}
20+
)
21+
22+
postRenderer, err := blogrenderer.NewPostRenderer()
23+
24+
if err != nil {
25+
t.Fatal(err)
26+
}
27+
28+
t.Run("it converts a single post into HTML", func(t *testing.T) {
29+
buf := bytes.Buffer{}
30+
31+
if err := postRenderer.Render(&buf, aPost); err != nil {
32+
t.Fatal(err)
33+
}
34+
35+
approvals.VerifyString(t, buf.String())
36+
})
37+
38+
t.Run("it renders an index of posts", func(t *testing.T) {
39+
buf := bytes.Buffer{}
40+
posts := []blogrenderer.Post{{Title: "Hello World"}, {Title: "Hello World 2"}}
41+
42+
if err := postRenderer.RenderIndex(&buf, posts); err != nil {
43+
t.Fatal(err)
44+
}
45+
46+
approvals.VerifyString(t, buf.String())
47+
})
48+
}
49+
50+
func BenchmarkRender(b *testing.B) {
51+
var (
52+
aPost = blogrenderer.Post{
53+
Title: "hello world",
54+
Body: "This is a post",
55+
Description: "This is a description",
56+
Tags: []string{"go", "tdd"},
57+
}
58+
)
59+
60+
postRenderer, err := blogrenderer.NewPostRenderer()
61+
62+
if err != nil {
63+
b.Fatal(err)
64+
}
65+
66+
b.ResetTimer()
67+
for i := 0; i < b.N; i++ {
68+
postRenderer.Render(io.Discard, aPost)
69+
}
70+
}

blogrenderer/templates/blog.gohtml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{{template "top" .}}
2+
<h1>{{.Title}}</h1>
3+
4+
<p>{{.Description}}</p>
5+
6+
Tags: <ul>{{range .Tags}}<li>{{.}}</li>{{end}}</ul>
7+
{{.HTMLBody}}
8+
{{template "bottom" .}}

blogrenderer/templates/bottom.gohtml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{{define "bottom"}}
2+
</main>
3+
<footer>
4+
<ul>
5+
<li><a href="https://twitter.com/quii">Twitter</a></li>
6+
<li><a href="https://github.com/quii">GitHub</a></li>
7+
</ul>
8+
</footer>
9+
</body>
10+
</html>
11+
{{end}}

blogrenderer/templates/index.gohtml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{{template "top" .}}
2+
<ol>{{range .}}<li><a href="/post/{{.SanitisedTitle}}">{{.Title}}</a></li>{{end}}</ol>
3+
{{template "bottom" .}}

blogrenderer/templates/top.gohtml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{define "top"}}<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>My amazing blog!</title>
5+
<meta charset="UTF-8"/>
6+
<meta name="description" content="Wow, like and subscribe, it really helps the channel guys" lang="en"/>
7+
</head>
8+
<body>
9+
<nav role="navigation">
10+
<div>
11+
<h1>Budding Gopher's blog</h1>
12+
<ul>
13+
<li><a href="/">home</a></li>
14+
<li><a href="about">about</a></li>
15+
<li><a href="archive">archive</a></li>
16+
</ul>
17+
</div>
18+
</nav>
19+
<main>
20+
{{end}}

build.books.sh

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ docker run --rm -v `pwd`:/data uppalabharath/pandoc-latex-cjk:latest --from=gfm+
2424
roman-numerals.md \
2525
math.md \
2626
reading-files.md \
27+
html-templates.md \
2728
intro-to-generics.md \
2829
app-intro.md \
2930
http-server.md \
@@ -58,6 +59,7 @@ docker run --rm -v `pwd`:/data uppalabharath/pandoc-latex-cjk:latest --from=gfm+
5859
roman-numerals.md \
5960
math.md \
6061
reading-files.md \
62+
html-templates.md \
6163
intro-to-generics.md \
6264
app-intro.md \
6365
http-server.md \

go.mod

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
module github.com/quii/learn-go-with-tests
22

3-
go 1.14
3+
go 1.16
44

55
require (
6+
github.com/approvals/go-approval-tests v0.0.0-20211008131110-0c40b30e0000
67
github.com/client9/misspell v0.3.4 // indirect
8+
github.com/gomarkdown/markdown v0.0.0-20211212230626-5af6ad2f47df
79
github.com/gorilla/websocket v1.4.2
810
github.com/po3rin/gofmtmd v0.1.3 // indirect
9-
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
1011
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
1112
golang.org/x/tools v0.1.8 // indirect
1213
)

go.sum

+4-31
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
2+
github.com/approvals/go-approval-tests v0.0.0-20211008131110-0c40b30e0000 h1:H152l3O+2XIXQu8IrqEXeqJOFCvSShUXs7+x0lw8V1k=
3+
github.com/approvals/go-approval-tests v0.0.0-20211008131110-0c40b30e0000/go.mod h1:PJOqSY8IofNv3heAD6k8E7EfFS6okiSS9bSAasaAUME=
24
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
35
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
46
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -8,8 +10,8 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
810
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
911
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1012
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
11-
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
12-
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
13+
github.com/gomarkdown/markdown v0.0.0-20211212230626-5af6ad2f47df h1:M7mdNDTRraBcrHZg2aOYiFP9yTDajb6fquRZRpXnbVA=
14+
github.com/gomarkdown/markdown v0.0.0-20211212230626-5af6ad2f47df/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
1315
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
1416
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
1517
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
@@ -37,61 +39,32 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
3739
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
3840
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
3941
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
40-
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
41-
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
42-
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
4342
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
4443
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
4544
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
4645
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
47-
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
48-
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
49-
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
50-
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI=
51-
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
5246
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
5347
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
5448
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
55-
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
56-
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
5749
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
5850
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
5951
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
60-
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
61-
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
62-
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
6352
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
6453
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
65-
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
6654
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
6755
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
6856
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
6957
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
70-
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
7158
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
72-
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
73-
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
7459
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
75-
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
76-
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
7760
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
7861
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
7962
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
80-
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
8163
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
8264
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
8365
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
8466
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
85-
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 h1:EBZoQjiKKPaLbPrbpssUfuHtwM6KV/vb4U85g/cigFY=
8667
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
87-
golang.org/x/tools v0.0.0-20201105001634-bc3cf281b174 h1:0rx0F4EjJNbxTuzWe0KjKcIzs+3VEb/Mrs/d1ciNz1c=
88-
golang.org/x/tools v0.0.0-20201105001634-bc3cf281b174/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
89-
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
90-
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
91-
golang.org/x/tools v0.1.4 h1:cVngSRcfgyZCzys3KYOpCFa+4dqX/Oub9tAq00ttGVs=
92-
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
93-
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
94-
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
9568
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
9669
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
9770
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

0 commit comments

Comments
 (0)