| // Copyright 2024 The Fuchsia 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 bazel_docgen |
| |
| import ( |
| "strings" |
| "text/template" |
| |
| pb "go.fuchsia.dev/fuchsia/tools/bazel-docgen/third_party/stardoc" |
| ) |
| |
| const ruleTemplate = ` |
| [TOC] |
| |
| # {{ .RuleName }} |
| |
| {{ .DocString }} |
| |
| ## **ATTRIBUTES** |
| |
| | Name | Description | Type | Mandatory | Default | |
| | :------------- | :------------- | :------------- | :------------- | :------------- | |
| {{range .Attribute }}| {{ .Name }} | {{description .DocString }} | {{attributeTypeString .Type }} | {{isMandatory .Mandatory }} | {{defaultValue .DefaultValue }} | |
| {{end }} |
| ` |
| |
| const providerTemplate = ` |
| [TOC] |
| |
| # {{ .ProviderName }} |
| |
| {{ .DocString }} |
| |
| {{if .FieldInfo }}## **FIELDS** |
| |
| |
| | Name | Description | |
| | :------------- | :------------- | |
| {{range .FieldInfo }}| {{ .Name }} | {{description .DocString }} | |
| {{end}}{{end}} |
| ` |
| |
| const starlarkFunctionTemplate = ` |
| [TOC] |
| |
| # {{ .FunctionName }} |
| |
| {{ .DocString }} |
| |
| {{if .Parameter }}## **PARAMETERS** |
| |
| |
| | Name | Description | Default | |
| | :------------- | :------------- | :------------- | |
| {{range .Parameter }}| {{ .Name }} | {{description .DocString }} | {{defaultValue .DefaultValue }} | |
| {{end}}{{end}} |
| |
| {{if .Return }} |
| **RETURNS** |
| |
| {{with .Return }}{{ .DocString }}{{end}} |
| {{end}} |
| ` |
| |
| const repositoryRuleTemplate = ` |
| [TOC] |
| |
| # {{ .RuleName }} |
| |
| {{ .DocString }} |
| |
| ## **ATTRIBUTES** |
| |
| | Name | Description | Type | Mandatory | Default | |
| | :------------- | :------------- | :------------- | :------------- | :------------- | |
| {{range .Attribute }}| {{ .Name }} | {{description .DocString }} | {{attributeTypeString .Type }} | {{isMandatory .Mandatory }} | {{defaultValue .DefaultValue }} | |
| {{end }} |
| |
| {{if .Environ}} |
| ## **ENVIRONMENT VARIABLES** |
| |
| This repository rule depends on the following environment variables: |
| |
| {{range .Environ}}* {{codeBlock .}}{{end}} |
| {{end}} |
| ` |
| |
| var ( |
| attributeTypeURLMap = map[pb.AttributeType]string{ |
| pb.AttributeType_INT: "int", |
| pb.AttributeType_LABEL: "label", |
| pb.AttributeType_STRING: "string", |
| pb.AttributeType_STRING_LIST: "string_list", |
| pb.AttributeType_INT_LIST: "int_list", |
| pb.AttributeType_LABEL_LIST: "label_list", |
| pb.AttributeType_BOOLEAN: "bool", |
| pb.AttributeType_LABEL_STRING_DICT: "label_keyed_string_dict", |
| pb.AttributeType_STRING_DICT: "string_dict", |
| pb.AttributeType_STRING_LIST_DICT: "string_list_dict", |
| pb.AttributeType_OUTPUT: "output", |
| pb.AttributeType_OUTPUT_LIST: "output_list", |
| } |
| attributeTypeReadableNameMap = map[pb.AttributeType]string{ |
| pb.AttributeType_INT: "Integer", |
| pb.AttributeType_LABEL: "Label", |
| pb.AttributeType_STRING: "String", |
| pb.AttributeType_STRING_LIST: "String List", |
| pb.AttributeType_INT_LIST: "Integer List", |
| pb.AttributeType_LABEL_LIST: "Label List", |
| pb.AttributeType_BOOLEAN: "Boolean", |
| pb.AttributeType_LABEL_STRING_DICT: "Label String Dict", |
| pb.AttributeType_STRING_DICT: "String Dict", |
| pb.AttributeType_STRING_LIST_DICT: "String List Dict", |
| pb.AttributeType_OUTPUT: "Output", |
| pb.AttributeType_OUTPUT_LIST: "Output List", |
| } |
| ) |
| |
| func defaultValue(value string) string { |
| if value == "" { |
| return "-" |
| } |
| // Return the value with backticks if there is one |
| return "`" + value + "`" |
| } |
| |
| func codeBlock(value string) string { |
| return "`" + value + "`" |
| } |
| |
| type stringReplacements struct { |
| input string |
| replacement string |
| } |
| |
| // Makes the description renderable inside of a markdown table. |
| // TODO: properly support code blocks. |
| func description(value string) string { |
| if value == "" { |
| return "-" |
| } |
| |
| // Replace the values of the description that would cause problems rendering |
| // in a table context. |
| replacements := []stringReplacements{ |
| {"<", "<"}, |
| {">", ">"}, |
| {"|", "\\|"}, |
| {"\n", "<br>"}, |
| } |
| value = strings.TrimSpace(value) |
| for _, r := range replacements { |
| value = strings.ReplaceAll(value, r.input, r.replacement) |
| } |
| return value |
| } |
| |
| func attributeTypeString(t pb.AttributeType) string { |
| if t == pb.AttributeType_NAME { |
| return "<a href=\"https://bazel.build/concepts/labels#target-names\">Name</a>" |
| } else if t == pb.AttributeType_UNKNOWN { |
| return "UKNOWN" |
| } else { |
| return "<a href=\"https://bazel.build/rules/lib/toplevel/attr#" + attributeTypeURLMap[t] + "\">" + attributeTypeReadableNameMap[t] + "</a>" |
| } |
| } |
| |
| func isMandatory(m bool) string { |
| if m { |
| return "required" |
| } else { |
| return "optional" |
| } |
| } |
| func NewRuleTemplate() (*template.Template, error) { |
| return makeTemplate("rule", ruleTemplate) |
| } |
| |
| func NewProviderTemplate() (*template.Template, error) { |
| return makeTemplate("provider", providerTemplate) |
| } |
| |
| func NewStarlarkFunctionTemplate() (*template.Template, error) { |
| return makeTemplate("starlark_function", starlarkFunctionTemplate) |
| } |
| |
| func NewRepositoryRuleTemplate() (*template.Template, error) { |
| return makeTemplate("repository_rule", repositoryRuleTemplate) |
| } |
| |
| func makeTemplate(name string, templateString string) (*template.Template, error) { |
| t := template.New(name) |
| t.Funcs( |
| template.FuncMap{ |
| "defaultValue": defaultValue, |
| "description": description, |
| "attributeTypeString": attributeTypeString, |
| "isMandatory": isMandatory, |
| "codeBlock": codeBlock, |
| }, |
| ) |
| return t.Parse(templateString) |
| } |