pulumi/pkg/codegen/docs/description.go

129 lines
4.2 KiB
Go

// Copyright 2016-2020, Pulumi Corporation.
//
// 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
//
// http://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.
package docs
import (
"fmt"
"strings"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
)
const (
beginCodeBlock = "<!--Start PulumiCodeChooser -->"
endCodeBlock = "<!--End PulumiCodeChooser -->"
)
type codeLocation struct {
open int
close int
}
func getCodeSection(doc string) []codeLocation {
var fences []codeLocation
startIndex := 0
for {
open := strings.Index(doc[startIndex:], beginCodeBlock)
if open == -1 {
break
}
var fence codeLocation
fence.open = startIndex + open
startIndex += open + len(beginCodeBlock)
closing := strings.Index(doc[startIndex:], endCodeBlock)
contract.Assertf(closing != -1, "this should never happen: "+
"there should be equal amounts of opening and closing code block markers")
fence.close = startIndex + closing
startIndex += closing + len(endCodeBlock)
fences = append(fences, fence)
}
return fences
}
func markupBlock(block, supportedSnippetLanguages string) string {
languages := []struct{ tag, choosable string }{
{"typescript", "<div>\n<pulumi-choosable type=\"language\" values=\"javascript,typescript\">\n\n"},
{"python", "<div>\n<pulumi-choosable type=\"language\" values=\"python\">\n\n"},
{"go", "<div>\n<pulumi-choosable type=\"language\" values=\"go\">\n\n"},
{"csharp", "<div>\n<pulumi-choosable type=\"language\" values=\"csharp\">\n\n"},
{"java", "<div>\n<pulumi-choosable type=\"language\" values=\"java\">\n\n"},
{"yaml", "<div>\n<pulumi-choosable type=\"language\" values=\"yaml\">\n\n"},
}
const (
//nolint:lll
chooserStartFmt = "<div>\n<pulumi-chooser type=\"language\" options=\"%s\"></pulumi-chooser>\n</div>\n"
choosableEnd = "</pulumi-choosable>\n</div>\n"
)
var markedUpBlock strings.Builder
// first, append the start chooser
markedUpBlock.WriteString(fmt.Sprintf(chooserStartFmt, supportedSnippetLanguages))
for _, lang := range languages {
// Add language specific open choosable
markedUpBlock.WriteString(lang.choosable)
// find our language - because we have no guarantee of order from our input, we need to find
// both code fences and then append the content in the order that docsgen expects.
start := strings.Index(block, "```"+lang.tag)
if start == -1 {
markedUpBlock.WriteString("```\n")
markedUpBlock.WriteString(defaultMissingExampleSnippetPlaceholder)
markedUpBlock.WriteString("\n```\n")
} else {
// find end index - this is the next code fence.
endLangBlock := start + len("```"+lang.tag) + strings.Index(block[start+len("```"+lang.tag):], "```")
// append code to block, and include code fences
markedUpBlock.WriteString(block[start : endLangBlock+len("```")])
markedUpBlock.WriteRune('\n')
}
// add closing choosable
markedUpBlock.WriteString(choosableEnd)
}
return markedUpBlock.String()
}
func (dctx *docGenContext) processDescription(description, supportedSnippetLanguages string) docInfo {
importDetails := ""
parts := strings.Split(description, "\n\n## Import")
if len(parts) > 1 {
importDetails = parts[1]
description = parts[0]
}
codeBlocks := getCodeSection(description)
startIndex := 0
var markedUpDescription string
for _, block := range codeBlocks {
// append text
markedUpDescription += description[startIndex:block.open]
codeBlock := description[block.open:block.close]
// append marked up block
markedUpDescription += markupBlock(codeBlock, supportedSnippetLanguages)
startIndex = block.close + len(endCodeBlock)
}
// append remainder of description, if any
markedUpDescription += description[startIndex:]
return docInfo{
description: markedUpDescription,
importDetails: importDetails,
}
}