func ExtractCodeBlocksFromAst()

in internal/parsers/markdown.go [91:199]


func ExtractCodeBlocksFromAst(
	node ast.Node,
	source []byte,
	languagesToExtract []string,
) []CodeBlock {
	var lastHeader string
	var commands []CodeBlock
	var nextBlockIsExpectedOutput bool
	var lastExpectedSimilarityScore float64
	var lastExpectedRegex *regexp.Regexp
	var lastNode ast.Node

	ast.Walk(node, func(node ast.Node, entering bool) (ast.WalkStatus, error) {
		if entering {
			switch n := node.(type) {
			// Set the last header when we encounter a heading.
			case *ast.Heading:
				lastHeader = string(extractTextFromMarkdown(&n.BaseBlock, source))
				lastNode = node
			case *ast.Paragraph:
				lastNode = node
			// Extract the code block if it matches the language.
			case *ast.HTMLBlock:
				content := extractTextFromMarkdown(&n.BaseBlock, source)
				matches := expectedSimilarityRegex.FindStringSubmatch(content)

				if len(matches) < 3 {
					break
				}

				match := matches[1]
				if match != "" {
					score, err := strconv.ParseFloat(match, 64)
					logging.GlobalLogger.Debugf("Simalrity score of %f found", score)
					if err != nil {
						return ast.WalkStop, err
					}
					lastExpectedSimilarityScore = score
				} else {
					match = matches[2]
					logging.GlobalLogger.Debugf("Regex %q found", match)

					if match == "" {
						return ast.WalkStop, errors.New("No regex found")
					}

					re, err := regexp.Compile(match)
					if err != nil {
						return ast.WalkStop, fmt.Errorf("Cannot compile the following regex: %q", match)
					}

					lastExpectedRegex = re
				}

				nextBlockIsExpectedOutput = true
			case *ast.FencedCodeBlock:
				language := string(n.Language((source)))
				content := extractTextFromMarkdown(&n.BaseBlock, source)
				description := ""

				if lastNode != nil {
					switch n := lastNode.(type) {
					case *ast.Paragraph:
						description = string(extractTextFromMarkdown(&n.BaseBlock, source))
					default:
						logging.GlobalLogger.Warnf("The node before the codeblock `%s` is not a paragraph, it is a %s", content, n.Kind())
					}
				} else {
					logging.GlobalLogger.Warnf("There are no markdown elements before the last codeblock `%s`", content)
				}

				lastNode = node
				for _, desiredLanguage := range languagesToExtract {
					if language == desiredLanguage {
						command := CodeBlock{
							Language:    language,
							Content:     content,
							Header:      lastHeader,
							Description: description,
						}
						commands = append(commands, command)
						break
					} else if nextBlockIsExpectedOutput {
						// Map the expected output to the last command. If there
						// are no commands, then we ignore the expected output.
						if len(commands) > 0 {
							expectedOutputBlock := ExpectedOutputBlock{
								Language:           language,
								Content:            extractTextFromMarkdown(&n.BaseBlock, source),
								ExpectedSimilarity: lastExpectedSimilarityScore,
								ExpectedRegex:      lastExpectedRegex,
							}
							commands[len(commands)-1].ExpectedOutput = expectedOutputBlock

							// Reset the expected output state.
							nextBlockIsExpectedOutput = false
							lastExpectedSimilarityScore = 0
							lastExpectedRegex = nil
						}
						break
					}
				}
			}
		}
		return ast.WalkContinue, nil
	})

	return commands
}