* Copyright 2020 The Go Authors. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file.

package frontend

import (
	
	
	
	
	
	

	
	
	
	
	
	
	
	
	
)
astTransformer is a default transformer of the goldmark tree. We pass in readme information to use for the link transformations.
Transform transforms the given AST tree.
func ( *astTransformer) ( *ast.Document,  text.Reader,  parser.Context) {
	_ = ast.Walk(, func( ast.Node,  bool) (ast.WalkStatus, error) {
		if ! {
			return ast.WalkContinue, nil
		}
		switch v := .(type) {
		case *ast.Image:
			if  := translateLink(string(.Destination), .info, true, .readme);  != "" {
				.Destination = []byte()
			}
		case *ast.Link:
			if  := translateLink(string(.Destination), .info, false, .readme);  != "" {
				.Destination = []byte()
			}
		}
		return ast.WalkContinue, nil
	})
}
htmlRenderer is a renderer.NodeRenderer implementation that renders pkg.go.dev readme features.
firstHeading and offset are used to calculate the first heading tag's level in a readme.
newHTMLRenderer creates a new HTMLRenderer for a readme.
func ( *source.Info,  *internal.Readme,  ...html.Option) renderer.NodeRenderer {
	 := &htmlRenderer{
		info:         ,
		readme:       ,
		Config:       html.NewConfig(),
		firstHeading: true,
		offset:       0,
	}
	for ,  := range  {
		.SetHTMLOption(&.Config)
	}
	return 
}
RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs.
The offset ensures the first heading is always an <h3>.
		.offset = 3 - .Level
		.firstHeading = false
	}
	 := .Level + .offset
	if  {
		if .Level > 6 {
			_, _ = .WriteString(fmt.Sprintf(`<div class="h%d" role="heading" aria-level="%d"`, , .Level))
		} else {
			_, _ = .WriteString(fmt.Sprintf(`<h%d class="h%d"`, , .Level))
		}
		if .Attributes() != nil {
			html.RenderAttributes(, , html.HeadingAttributeFilter)
		}
		_ = .WriteByte('>')
	} else {
		if .Level > 6 {
			_, _ = .WriteString("</div>\n")
		} else {
			_, _ = .WriteString(fmt.Sprintf("</h%d>\n", ))
		}
	}
	return ast.WalkContinue, nil
}
renderHTMLBlock is copied directly from the goldmark source code and modified to call translateHTML in every block
func ( *htmlRenderer) ( util.BufWriter,  []byte,  ast.Node,  bool) (ast.WalkStatus, error) {
	 := .(*ast.HTMLBlock)
	if  {
		if .Unsafe {
			 := .Lines().Len()
			for  := 0;  < ; ++ {
				 := .Lines().At()
				,  := translateHTML(.Value(), .info, .readme)
				if  != nil {
					return ast.WalkStop, 
				}
				_, _ = .Write()
			}
		} else {
			_, _ = .WriteString("<!-- raw HTML omitted -->\n")
		}
	} else {
		if .HasClosure() {
			if .Unsafe {
				 := .ClosureLine
				_, _ = .Write(.Value())
			} else {
				_, _ = .WriteString("<!-- raw HTML omitted -->\n")
			}
		}
	}
	return ast.WalkContinue, nil
}

func ( *htmlRenderer) ( util.BufWriter,  []byte,  ast.Node,  bool) (ast.WalkStatus, error) {
	if ! {
		return ast.WalkSkipChildren, nil
	}
	if .Unsafe {
		 := .(*ast.RawHTML)
		for  := 0;  < .Segments.Len(); ++ {
			 := .Segments.At()
			,  := translateHTML(.Value(), .info, .readme)
			if  != nil {
				return ast.WalkStop, 
			}
			_, _ = .Write()
		}
		return ast.WalkSkipChildren, nil
	}
	_, _ = .WriteString("<!-- raw HTML omitted -->")
	return ast.WalkSkipChildren, nil
}
ids is a collection of element ids in document.
type ids struct {
	values map[string]bool
}
newIDs creates a collection of element ids in a document.
func () parser.IDs {
	return &ids{
		values: map[string]bool{},
	}
}
Generate turns heading content from a markdown document into a heading id. First HTML markup and markdown images are stripped then unicode letters and numbers are used to generate the final result. Finally, all heading ids are prefixed with "readme-" to avoid name collisions with other ids on the unit page. Duplicated heading ids are given an incremental suffix. See readme_test.go for examples.
Matches strings like `<tag attr="value">Text</tag>` or `[![Text](file.svg)](link.html)`.
	 := regexp.MustCompile(`(<[^<>]+>|\[\!\[[^\]]+]\([^\)]+\)\]\([^\)]+\))`)
	 := .ReplaceAllString(string(), "")
	 := func( rune) bool {
		return !unicode.IsLetter() && !unicode.IsNumber()
	}
	 = strings.Join(strings.FieldsFunc(, ), "-")
	 = strings.ToLower()
	if len() == 0 {
		if  == ast.KindHeading {
			 = "heading"
		} else {
			 = "id"
		}
	}
	 := 
	for  := 1; ; ++ {
		if ,  := .values[]; ! {
			.values[] = true
			break
		}
		 = fmt.Sprintf("%s-%d", , )
	}
	return []byte("readme-" + )
}
Put implements Put from the goldmark parser IDs interface.
func ( *ids) ( []byte) {
	.values[string()] = true
}

type extractLinks struct {
	ctx            context.Context
	inLinksHeading bool
	links          []link
}
The name of the heading from which we extract links.
const linkHeadingText = "Links"

var linkHeadingBytes = []byte(linkHeadingText) // for faster comparison to node contents
Transform extracts links from the "Links" section of a README.
func ( *extractLinks) ( *ast.Document,  text.Reader,  parser.Context) {
	 := ast.Walk(, func( ast.Node,  bool) (ast.WalkStatus, error) {
		if ! {
			return ast.WalkContinue, nil
		}
		switch n := .(type) {

We are in the links heading from the point we see a heading with linkHeadingText until the point we see the next heading.
When in the links heading, extract links from list items.
We expect the pattern: ListItem -> TextBlock -> Link, with no other children.
			if ,  := .FirstChild().(*ast.TextBlock);  {
Record the link.
					.links = append(.links, link{
						Href: string(.Destination),
						Body: string(.Text(.Source())),
					})
				}
			}
			return ast.WalkSkipChildren, nil
		}

		return ast.WalkContinue, nil
	})
	if  != nil {
		log.Errorf(.ctx, "extractLinks.Transform: %v", )
	}
}

type extractTOC struct {
	ctx         context.Context
	Headings    []*Heading
	removeTitle bool // omit title from TOC
}
Transform collects the headings from a readme into an outline of the document. It nests the headings based on the h-level hierarchy. See tests for heading levels in TestReadme for behavior.
func ( *extractTOC) ( *ast.Document,  text.Reader,  parser.Context) {
	var  []*Heading
	 := ast.Walk(, func( ast.Node,  bool) (ast.WalkStatus, error) {
		if .Kind() == ast.KindHeading &&  {
			var  bytes.Buffer
We keep only text content from the headings in the first pass.
				if .Kind() == ast.KindText {
					.Write(.Text(.Source()))
				}
If the buffer is empty we take the text content from non-text nodes.
			if .Len() == 0 {
				for  := .FirstChild();  != nil;  = .NextSibling() {
					.Write(.Text(.Source()))
				}
			}
			 := .(*ast.Heading)
			 := &Heading{
				Level: .Level,
				Text:  .String(),
			}
			if ,  := .AttributeString("id");  {
				.ID = string(.([]byte))
			}
			 = append(, )
			return ast.WalkSkipChildren, nil
		}
		return ast.WalkContinue, nil
	})
	if  != nil {
		log.Errorf(.ctx, "extractTOC.Transform: %v", )
	}
We nest the headings by walking through the list we extracted and establishing parent child relationships based on heading levels.
	var  []*Heading
	for ,  := range  {
		if  == 0 {
			 = append(, )
			continue
		}
		 := [-1]
		for  != nil && .Level >= .Level {
			 = .parent
		}
		if  == nil {
			 = append(, )
		} else {
			.parent = 
			.Children = append(.Children, )
		}
	}
If there is only one top tevel heading with 1 or more children we assume it is the title of the document and remove it from the TOC.
		if len() == 1 && len([0].Children) > 0 {
			 = [0].Children
		}
	}
	.Headings =