You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: parser.go
    path of file: ./repos/jira-cli/pkg/md/jirawiki
    
    the code of the file until where you have to start completion: package jirawiki

import (
	"fmt"
	"strings"
)

// Supported Jira wiki tags.
const (
	TagHeading1      = "h1."
	TagHeading2      = "h2."
	TagHeading3      = "h3."
	TagHeading4      = "h4."
	TagHeading5      = "h5."
	TagHeading6      = "h6."
	TagBlockQuote    = "bq."
	TagQuote         = "{quote}"
	TagPanel         = "{panel}"
	TagCodeBlock     = "{code}"
	TagNoFormat      = "{noformat}"
	TagLink          = "["
	TagOrderedList   = "#"
	TagUnorderedList = "*" // '*' can be either be bold or an unordered list ðŸ¤¦.
	TagBold          = "*"
	TagTable         = "||"

	// Let's group tags based on their behavior.
	typeTagTextEffect    = "text-effect"
	typeTagList          = "list"
	typeTagHeading       = "heading"
	typeTagInlineQuote   = "inline-quote"
	typeTagReferenceLink = "link"
	typeTagFencedCode    = "code"
	typeTagTable         = "table"
	typeTagOther         = "other"

	// Supported attributes.
	attrTitle = "title"

	// Line feeds.
	newLine        = '\n'
	carriageReturn = '\r'
)

var validTags = []string{
	TagHeading1,
	TagHeading2,
	TagHeading3,
	TagHeading4,
	TagHeading5,
	TagHeading6,
	TagBlockQuote,
	TagQuote,
	TagPanel,
	TagCodeBlock,
	TagNoFormat,
	TagLink,
	TagOrderedList,
	TagUnorderedList,
	TagBold,
	TagTable,
}

var replacements = map[string]string{
	TagHeading1:    "#",  // '#' can be either be a h1 tag or an ordered list ðŸ¤·.
	TagHeading2:
    
func secondPass(lines []string) string {
	var (
		out     strings.Builder
		lineNum int
	)

	for lineNum < len(lines) {
		line := lines[lineNum]
		tokens := tokenize(line)

		if len(tokens) == 0 {
			out.WriteString(line)

			lineNum++
			if lineNum < len(lines)-1 {
				out.WriteRune(newLine)
			}
			continue
		}

		var beg int

	out:
		for beg < len(line) {
			end := beg

			if token, ok := tokenStarts(beg, tokens); ok {
				switch token.family {
				case typeTagTextEffect:
					end = token.handleTextEffects(line, &out)
				case typeTagHeading:
					end = token.handleHeadings(line, &out)
				case typeTagInlineQuote:
					end = token.handleInlineBlockQuote(line, &out)
				case typeTagList:
					end = token.handleList(line, &out)
				case typeTagFencedCode:
					lineNum = token.handleFencedCodeBlock(lineNum, lines, &out)
					break out
				case typeTagReferenceLink:
					end = token.handleReferenceLink(line, &out)
				case typeTagTable:
					end = token.handleTable(line, &out)
				case typeTagOther:
					if token.tag == TagQuote {
						// If end is same as size of the input, it implies that
						// we've found a closing token, and we will ignore it.
						if token.endIdx != len(line)-1 {
							out.WriteString(fmt.Sprintf("\n%s", replacements[token.tag]))
						}
					} else {
						out.WriteString(fmt.Sprintf("\n%s", replacements[token.tag]))
					}

					if token.tag == TagPanel {
						if t, ok := token.attrs[attrTitle]; ok {
							out.WriteString(fmt.Sprintf("\n**%s**\n", t))
						}

						if token.endIdx != len(line)-1 {
							out.WriteRune(newLine)
						}
					}

					end = token.endIdx
				}
			} else {
				out.WriteRune(rune(line[beg]))
			}

			end++
			beg = end
		}

		lineNum++
		out.WriteRune(newLine)
	}

	return out.String()
}