-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do not render empty code choosers on generated index page #2822
Changes from 5 commits
4b174a0
d31e039
6ff82b2
c1ee08d
5fb65af
eb4af28
b41002c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -66,6 +66,12 @@ | |||||
return nil, err | ||||||
} | ||||||
|
||||||
// If the code translation resulted in an empty examples section, remove it | ||||||
contentStr, err = removeEmptyExamples(contentStr) | ||||||
if err != nil { | ||||||
return nil, err | ||||||
} | ||||||
|
||||||
// Apply post-code translation edit rules. This applies all default edit rules and provider-supplied edit rules in | ||||||
// the post-code translation phase. | ||||||
contentBytes, err = g.editRules.apply(docFile.FileName, []byte(contentStr), info.PostCodeTranslation) | ||||||
|
@@ -221,9 +227,6 @@ | |||||
|
||||||
// This function renders the Pulumi.yaml config file for a given language if configuration is included in the example. | ||||||
func processConfigYaml(pulumiYAML, lang string) string { | ||||||
if pulumiYAML == "" { | ||||||
return pulumiYAML | ||||||
} | ||||||
// Replace the project name from the default `/` to a more descriptive name | ||||||
nameRegex := regexp.MustCompile(`name: /*`) | ||||||
pulumiYAMLFile := nameRegex.ReplaceAllString(pulumiYAML, "name: configuration-example") | ||||||
|
@@ -253,30 +256,53 @@ | |||||
return "", err | ||||||
} | ||||||
|
||||||
// If both PCL and PulumiYAML fields are empty, we can return. | ||||||
if pclExample.PulumiYAML == "" && pclExample.PCL == "" { | ||||||
return "", nil | ||||||
} | ||||||
|
||||||
// If we have a valid provider config but no additional code, we only render a YAML configuration block | ||||||
// with no choosers and an empty language runtime field | ||||||
if pclExample.PulumiYAML != "" && pclExample.PCL == "" { | ||||||
if pclExample.PCL == "" { | ||||||
return processConfigYaml(pclExample.PulumiYAML, ""), nil | ||||||
} | ||||||
} | ||||||
|
||||||
langs := genLanguageToSlice(g.language) | ||||||
const ( | ||||||
chooserStart = `{{< chooser language "typescript,python,go,csharp,java,yaml" >}}` + "\n" | ||||||
chooserEnd = "{{< /chooser >}}\n" | ||||||
choosableEnd = "\n{{% /choosable %}}\n" | ||||||
) | ||||||
exampleContent := chooserStart | ||||||
successfulConversion := false | ||||||
|
||||||
// Generate each language in turn and mark up the output with the correct Hugo shortcodes. | ||||||
for _, lang := range langs { | ||||||
choosableStart := fmt.Sprintf("{{%% choosable language %s %%}}\n", lang) | ||||||
|
||||||
// Generate the Pulumi.yaml config file for each language | ||||||
configFile := pclExample.PulumiYAML | ||||||
pulumiYAML := processConfigYaml(configFile, lang) | ||||||
var pulumiYAML string | ||||||
if pclExample.PulumiYAML != "" { | ||||||
pulumiYAML = processConfigYaml(pclExample.PulumiYAML, lang) | ||||||
} | ||||||
|
||||||
// Generate language example | ||||||
convertedLang, err := converter.singleExampleFromPCLToLanguage(pclExample, lang) | ||||||
if err != nil { | ||||||
g.warn(err.Error()) | ||||||
} | ||||||
if convertedLang != exampleUnavailable { | ||||||
successfulConversion = true | ||||||
} | ||||||
exampleContent += choosableStart + pulumiYAML + convertedLang + choosableEnd | ||||||
} | ||||||
exampleContent += chooserEnd | ||||||
return exampleContent, nil | ||||||
|
||||||
if successfulConversion { | ||||||
return exampleContent + chooserEnd, nil | ||||||
} | ||||||
return "", nil | ||||||
} | ||||||
|
||||||
type titleRemover struct{} | ||||||
|
@@ -477,3 +503,39 @@ | |||||
capitalize := cases.Title(language.English) | ||||||
return capitalize.String(providerName) | ||||||
} | ||||||
|
||||||
func removeEmptyExamples(contentStr string) (string, error) { | ||||||
if checkExamplesEmpty(contentStr) { | ||||||
mybytes, err := SkipSectionByHeaderContent([]byte(contentStr), func(headerText string) bool { | ||||||
return headerText == "Example Usage" | ||||||
}) | ||||||
contentStr = string(mybytes) | ||||||
return contentStr, err | ||||||
} | ||||||
return contentStr, nil | ||||||
|
||||||
} | ||||||
guineveresaenger marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
func checkExamplesEmpty(contentStr string) bool { | ||||||
guineveresaenger marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
gm := goldmark.New(goldmark.WithExtensions(parse.TFRegistryExtension)) | ||||||
astNode := gm.Parser().Parse(text.NewReader([]byte(contentStr))) | ||||||
|
||||||
isEmpty := false | ||||||
|
||||||
err := ast.Walk(astNode, func(n ast.Node, entering bool) (ast.WalkStatus, error) { | ||||||
if section, ok := n.(*section.Section); ok && entering { | ||||||
sectionText := section.Text([]byte(contentStr)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of converting to text and then checking if nothing came out, can we do this with a more structured check: A section is empty if it has one child (the title). We can then get the content of the title and validate that. |
||||||
// A little confusingly, we check if the section text _only_ contains the title, "Example Usage". | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
// Non-empty sections contain the title + content, so if we see only the title, the section is empty. | ||||||
if string(sectionText) == "Example Usage" { | ||||||
isEmpty = true | ||||||
return ast.WalkStop, nil | ||||||
} | ||||||
} | ||||||
return ast.WalkContinue, nil | ||||||
}) | ||||||
contract.AssertNoErrorf(err, "impossible: ast.Walk should never error") | ||||||
|
||||||
return isEmpty | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this change makes sense:
If there are no errors (
!diag.HasErrors()
), butsource == ""
, should we really setsource = exampleUnavailable
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two reasons:
It is possible for
diag
to have no errors (for example, when the input is empty), which results insource
being empty. We can return an empty string, or declare that we currently have no example.It is also possible for
diag
to have errors but the conversion being successful regardless.Therefore it makes more sense to check for "what are we looking to display to the user" and if it comes up empty, say that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you put that in a comment on
if source == "" {
?