| // Copyright 2019 The Wuffs Authors. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //    https://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | // +build ignore | 
 |  | 
 | package main | 
 |  | 
 | // print-markdown-links.go prints a sorted list of the link targets in the | 
 | // given .md files (or directories containing .md files). | 
 | // | 
 | // Usage: go run print-markdown-links.go dirname0 filename1 etc | 
 | // | 
 | // For link targets that look like "/file/names" (as opposed to starting with | 
 | // web URLs starting with "http:" or "https:"), they are preceded by a '+' or a | 
 | // '-' depending on whether or not that file or directory exists, assuming that | 
 | // this script is run in the root directory to resolve filename links that | 
 | // start with a slash. | 
 | // | 
 | // Printing web URLs can be skipped entirely by passing -skiphttp | 
 | // | 
 | // For example, running: | 
 | //   go run script/print-markdown-links.go -skiphttp doc | grep "^-" | 
 | // can find broken Markdown links in the documentation. | 
 |  | 
 | import ( | 
 | 	"flag" | 
 | 	"fmt" | 
 | 	"io" | 
 | 	"io/ioutil" | 
 | 	"os" | 
 | 	"path/filepath" | 
 | 	"sort" | 
 | 	"strings" | 
 |  | 
 | 	"gopkg.in/russross/blackfriday.v2" | 
 | ) | 
 |  | 
 | var skiphttp = flag.Bool("skiphttp", false, `skip "http:" or "https:" links`) | 
 |  | 
 | func main() { | 
 | 	if err := main1(); err != nil { | 
 | 		os.Stderr.WriteString(err.Error() + "\n") | 
 | 		os.Exit(1) | 
 | 	} | 
 | } | 
 |  | 
 | func main1() error { | 
 | 	flag.Parse() | 
 | 	r := &renderer{ | 
 | 		links: map[string]struct{}{}, | 
 | 	} | 
 |  | 
 | 	for _, arg := range flag.Args() { | 
 | 		err := filepath.Walk(arg, func(path string, info os.FileInfo, walkErr error) error { | 
 | 			if walkErr != nil { | 
 | 				return walkErr | 
 | 			} | 
 | 			if info.IsDir() || !strings.HasSuffix(path, ".md") { | 
 | 				return nil | 
 | 			} | 
 | 			return visit(r, path) | 
 | 		}) | 
 | 		if err != nil { | 
 | 			return err | 
 | 		} | 
 | 	} | 
 |  | 
 | 	sorted := make([]string, 0, len(r.links)) | 
 | 	for k := range r.links { | 
 | 		sorted = append(sorted, k) | 
 | 	} | 
 | 	sort.Strings(sorted) | 
 |  | 
 | 	for _, s := range sorted { | 
 | 		mark := '-' | 
 | 		switch { | 
 | 		case strings.HasPrefix(s, "http:"), strings.HasPrefix(s, "https:"): | 
 | 			if *skiphttp { | 
 | 				continue | 
 | 			} | 
 | 			mark = ':' | 
 | 		case (len(s) > 0) && (s[0] == '/'): | 
 | 			filename := s[1:] | 
 | 			if i := strings.IndexByte(filename, '#'); i >= 0 { | 
 | 				filename = filename[:i] | 
 | 			} | 
 | 			if _, err := os.Stat(filename); err == nil { | 
 | 				mark = '+' | 
 | 			} | 
 | 		} | 
 | 		fmt.Printf("%c %s\n", mark, s) | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | func visit(r *renderer, filename string) error { | 
 | 	src, err := ioutil.ReadFile(filename) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 | 	blackfriday.Run(src, blackfriday.WithRenderer(r)) | 
 | 	return nil | 
 | } | 
 |  | 
 | type renderer struct { | 
 | 	links map[string]struct{} | 
 | } | 
 |  | 
 | func (r *renderer) RenderHeader(w io.Writer, n *blackfriday.Node) {} | 
 | func (r *renderer) RenderFooter(w io.Writer, n *blackfriday.Node) {} | 
 |  | 
 | func (r *renderer) RenderNode(w io.Writer, n *blackfriday.Node, entering bool) blackfriday.WalkStatus { | 
 | 	if entering { | 
 | 		if dst := n.LinkData.Destination; len(dst) != 0 { | 
 | 			r.links[string(dst)] = struct{}{} | 
 | 		} | 
 | 	} | 
 | 	return blackfriday.GoToNext | 
 | } |