Enable generating a table of contents in Stardoc (#203)
Adds a bool `generate_table_of_contents` to `stardoc()` to enable table of contents. This defaults to False for backwards compatibility. Adds a Label `table_of_contents_template` to `stardoc()` to specify the vm template.
The default table of contents template looks like this (from the test):
> ## Rules
>
> - [my_rule](#my_rule)
>
> ## Providers
>
> - [MyFooInfo](#MyFooInfo)
> - [MyVeryDocumentedInfo](#MyVeryDocumentedInfo)
>
> ## Functions
>
> - [check_sources](#check_sources)
> - [returns_a_thing](#returns_a_thing)
>
> ## Aspects
>
> - [my_aspect](#my_aspect)
> - [other_aspect](#other_aspect)
>
> ## Repository Rules
>
> - [my_repo](#my_repo)
>
> ## Module Extensions
>
> - [my_ext](#my_ext)
diff --git a/docs/stardoc_rule.md b/docs/stardoc_rule.md
index 18bb219..cf79770 100644
--- a/docs/stardoc_rule.md
+++ b/docs/stardoc_rule.md
@@ -8,9 +8,9 @@
<pre>
stardoc(<a href="#stardoc-name">name</a>, <a href="#stardoc-input">input</a>, <a href="#stardoc-out">out</a>, <a href="#stardoc-deps">deps</a>, <a href="#stardoc-format">format</a>, <a href="#stardoc-symbol_names">symbol_names</a>, <a href="#stardoc-semantic_flags">semantic_flags</a>, <a href="#stardoc-stardoc">stardoc</a>, <a href="#stardoc-renderer">renderer</a>,
- <a href="#stardoc-aspect_template">aspect_template</a>, <a href="#stardoc-func_template">func_template</a>, <a href="#stardoc-header_template">header_template</a>, <a href="#stardoc-provider_template">provider_template</a>, <a href="#stardoc-rule_template">rule_template</a>,
- <a href="#stardoc-repository_rule_template">repository_rule_template</a>, <a href="#stardoc-module_extension_template">module_extension_template</a>, <a href="#stardoc-use_starlark_doc_extract">use_starlark_doc_extract</a>,
- <a href="#stardoc-render_main_repo_name">render_main_repo_name</a>, <a href="#stardoc-kwargs">kwargs</a>)
+ <a href="#stardoc-aspect_template">aspect_template</a>, <a href="#stardoc-func_template">func_template</a>, <a href="#stardoc-header_template">header_template</a>, <a href="#stardoc-table_of_contents_template">table_of_contents_template</a>,
+ <a href="#stardoc-provider_template">provider_template</a>, <a href="#stardoc-rule_template">rule_template</a>, <a href="#stardoc-repository_rule_template">repository_rule_template</a>, <a href="#stardoc-module_extension_template">module_extension_template</a>,
+ <a href="#stardoc-use_starlark_doc_extract">use_starlark_doc_extract</a>, <a href="#stardoc-render_main_repo_name">render_main_repo_name</a>, <a href="#stardoc-kwargs">kwargs</a>)
</pre>
Generates documentation for exported starlark rule definitions in a target starlark file.
@@ -32,6 +32,7 @@
| <a id="stardoc-aspect_template"></a>aspect_template | The input file template for generating documentation of aspects | `Label("@io_bazel_stardoc//stardoc:templates/markdown_tables/aspect.vm")` |
| <a id="stardoc-func_template"></a>func_template | The input file template for generating documentation of functions. | `Label("@io_bazel_stardoc//stardoc:templates/markdown_tables/func.vm")` |
| <a id="stardoc-header_template"></a>header_template | The input file template for the header of the output documentation. | `Label("@io_bazel_stardoc//stardoc:templates/markdown_tables/header.vm")` |
+| <a id="stardoc-table_of_contents_template"></a>table_of_contents_template | The input file template for the table of contents of the output documentation. This is unset by default for backwards compatibility. Use `Label("@stardoc//stardoc:templates/markdown_tables/table_of_contents.vm")` for the default template. | `None` |
| <a id="stardoc-provider_template"></a>provider_template | The input file template for generating documentation of providers. | `Label("@io_bazel_stardoc//stardoc:templates/markdown_tables/provider.vm")` |
| <a id="stardoc-rule_template"></a>rule_template | The input file template for generating documentation of rules. | `Label("@io_bazel_stardoc//stardoc:templates/markdown_tables/rule.vm")` |
| <a id="stardoc-repository_rule_template"></a>repository_rule_template | The input file template for generating documentation of repository rules. This template is used only when using the native `starlark_doc_extract` rule. | `Label("@io_bazel_stardoc//stardoc:templates/markdown_tables/repository_rule.vm")` |
diff --git a/src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java
index 39b11df..9bf7cf7 100644
--- a/src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java
+++ b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java
@@ -22,6 +22,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.skydoc.rendering.MarkdownRenderer;
+import com.google.devtools.build.skydoc.rendering.MarkdownRenderer.Renderer;
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.AspectInfo;
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.AttributeInfo;
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ModuleExtensionInfo;
@@ -75,6 +76,7 @@
MarkdownRenderer renderer =
new MarkdownRenderer(
rendererOptions.headerTemplateFilePath,
+ rendererOptions.tableOfContentsTemplateFilePath,
rendererOptions.ruleTemplateFilePath,
rendererOptions.providerTemplateFilePath,
rendererOptions.funcTemplateFilePath,
@@ -83,18 +85,78 @@
rendererOptions.moduleExtensionTemplateFilePath,
!moduleInfo.getFile().isEmpty() ? moduleInfo.getFile() : "...");
+ // rules are printed sorted by their qualified name, and their attributes are sorted by name,
+ // with ATTRIBUTE_ORDERING specifying a fixed sort order for some standard attributes.
+ ImmutableList<RuleInfo> sortedRuleInfos =
+ moduleInfo.getRuleInfoList().stream()
+ .map(RendererMain::withSortedRuleAttributes)
+ .sorted(comparing(RuleInfo::getRuleName))
+ .collect(toImmutableList());
+
+ // providers are printed sorted by their qualified name.
+ ImmutableList<ProviderInfo> sortedProviderInfos =
+ ImmutableList.sortedCopyOf(
+ comparing(ProviderInfo::getProviderName), moduleInfo.getProviderInfoList());
+
+ // functions are printed sorted by their qualified name.
+ ImmutableList<StarlarkFunctionInfo> sortedStarlarkFunctions =
+ ImmutableList.sortedCopyOf(
+ comparing(StarlarkFunctionInfo::getFunctionName), moduleInfo.getFuncInfoList());
+
+ // aspects are printed sorted by their qualified name.
+ ImmutableList<AspectInfo> sortedAspectInfos =
+ ImmutableList.sortedCopyOf(
+ comparing(AspectInfo::getAspectName), moduleInfo.getAspectInfoList());
+
+ // Repository rules are printed sorted by their qualified name, and their attributes are
+ // sorted by name, with ATTRIBUTE_ORDERING specifying a fixed sort order for some standard
+ // attributes.
+ ImmutableList<RepositoryRuleInfo> sortedRepositoryRuleInfos =
+ moduleInfo.getRepositoryRuleInfoList().stream()
+ .map(RendererMain::withSortedRuleAttributes)
+ .sorted(comparing(RepositoryRuleInfo::getRuleName))
+ .collect(toImmutableList());
+
+ // Module extension are printed sorted by their qualified name, and their tag classes'
+ // attributes are sorted by name, with ATTRIBUTE_ORDERING specifying a fixed sort order for
+ // some standard attributes.
+ ImmutableList<ModuleExtensionInfo> sortedModuleExtensionInfos =
+ moduleInfo.getModuleExtensionInfoList().stream()
+ .map(RendererMain::withSortedTagAttributes)
+ .sorted(comparing(ModuleExtensionInfo::getExtensionName))
+ .collect(toImmutableList());
+
printWriter.println(renderer.renderMarkdownHeader(moduleInfo));
- printRuleInfos(printWriter, renderer, moduleInfo.getRuleInfoList());
- printProviderInfos(printWriter, renderer, moduleInfo.getProviderInfoList());
- printStarlarkFunctions(printWriter, renderer, moduleInfo.getFuncInfoList());
- printAspectInfos(printWriter, renderer, moduleInfo.getAspectInfoList());
- printRepositoryRuleInfos(printWriter, renderer, moduleInfo.getRepositoryRuleInfoList());
- printModuleExtensionInfos(printWriter, renderer, moduleInfo.getModuleExtensionInfoList());
+ if (rendererOptions.tableOfContentsTemplateFilePath != null) {
+ printWriter.println(
+ renderer.renderTableOfContents(
+ sortedRuleInfos,
+ sortedProviderInfos,
+ sortedStarlarkFunctions,
+ sortedAspectInfos,
+ sortedRepositoryRuleInfos,
+ sortedModuleExtensionInfos));
+ }
+ print(printWriter, renderer::render, sortedRuleInfos);
+ print(printWriter, renderer::render, sortedProviderInfos);
+ print(printWriter, renderer::render, sortedStarlarkFunctions);
+ print(printWriter, renderer::render, sortedAspectInfos);
+ print(printWriter, renderer::render, sortedRepositoryRuleInfos);
+ print(printWriter, renderer::render, sortedModuleExtensionInfos);
+
} catch (InvalidProtocolBufferException e) {
throw new IllegalArgumentException("Input file is not a valid ModuleInfo proto.", e);
}
}
+ private static <T> void print(PrintWriter printWriter, Renderer<T> renderer, List<T> infos)
+ throws IOException {
+ for (T info : infos) {
+ printWriter.println(renderer.render(info));
+ printWriter.println();
+ }
+ }
+
// A copy of com.google.devtools.build.docgen.DocgenConsts.ATTRIBUTE_ORDERING - we duplicate the
// ordering here because we intend to move this file from the Bazel tree to the Stardoc repo.
private static final ImmutableMap<String, Integer> ATTRIBUTE_ORDERING =
@@ -167,94 +229,5 @@
.build();
}
- private static void printRuleInfos(
- PrintWriter printWriter, MarkdownRenderer renderer, List<RuleInfo> ruleInfos)
- throws IOException {
- // rules are printed sorted by their qualified name, and their attributes are sorted by name,
- // with ATTRIBUTE_ORDERING specifying a fixed sort order for some standard attributes.
- ImmutableList<RuleInfo> sortedRuleInfos =
- ruleInfos.stream()
- .map(RendererMain::withSortedRuleAttributes)
- .sorted(comparing(RuleInfo::getRuleName))
- .collect(toImmutableList());
- for (RuleInfo ruleProto : sortedRuleInfos) {
- printWriter.println(renderer.render(ruleProto.getRuleName(), ruleProto));
- printWriter.println();
- }
- }
-
- private static void printProviderInfos(
- PrintWriter printWriter, MarkdownRenderer renderer, List<ProviderInfo> providerInfos)
- throws IOException {
- // providers are printed sorted by their qualified name.
- ImmutableList<ProviderInfo> sortedProviderInfos =
- ImmutableList.sortedCopyOf(comparing(ProviderInfo::getProviderName), providerInfos);
- for (ProviderInfo providerProto : sortedProviderInfos) {
- printWriter.println(renderer.render(providerProto.getProviderName(), providerProto));
- printWriter.println();
- }
- }
-
- private static void printStarlarkFunctions(
- PrintWriter printWriter,
- MarkdownRenderer renderer,
- List<StarlarkFunctionInfo> starlarkFunctions)
- throws IOException {
- // functions are printed sorted by their qualified name.
- ImmutableList<StarlarkFunctionInfo> sortedStarlarkFunctions =
- ImmutableList.sortedCopyOf(
- comparing(StarlarkFunctionInfo::getFunctionName), starlarkFunctions);
- for (StarlarkFunctionInfo funcProto : sortedStarlarkFunctions) {
- printWriter.println(renderer.render(funcProto));
- printWriter.println();
- }
- }
-
- private static void printAspectInfos(
- PrintWriter printWriter, MarkdownRenderer renderer, List<AspectInfo> aspectInfos)
- throws IOException {
- // aspects are printed sorted by their qualified name.
- ImmutableList<AspectInfo> sortedAspectInfos =
- ImmutableList.sortedCopyOf(comparing(AspectInfo::getAspectName), aspectInfos);
- for (AspectInfo aspectProto : sortedAspectInfos) {
- printWriter.println(renderer.render(aspectProto.getAspectName(), aspectProto));
- printWriter.println();
- }
- }
-
- private static void printRepositoryRuleInfos(
- PrintWriter printWriter, MarkdownRenderer renderer, List<RepositoryRuleInfo> ruleInfos)
- throws IOException {
- // Repository rules are printed sorted by their qualified name, and their attributes are sorted
- // by name, with ATTRIBUTE_ORDERING specifying a fixed sort order for some standard attributes.
- ImmutableList<RepositoryRuleInfo> sortedRepositoryRuleInfos =
- ruleInfos.stream()
- .map(RendererMain::withSortedRuleAttributes)
- .sorted(comparing(RepositoryRuleInfo::getRuleName))
- .collect(toImmutableList());
- for (RepositoryRuleInfo repositoryRuleProto : sortedRepositoryRuleInfos) {
- printWriter.println(renderer.render(repositoryRuleProto.getRuleName(), repositoryRuleProto));
- printWriter.println();
- }
- }
-
- private static void printModuleExtensionInfos(
- PrintWriter printWriter, MarkdownRenderer renderer, List<ModuleExtensionInfo> ruleInfos)
- throws IOException {
- // Module extension are printed sorted by their qualified name, and their tag classes'
- // attributes are sorted by name, with ATTRIBUTE_ORDERING specifying a fixed sort order for some
- // standard attributes.
- ImmutableList<ModuleExtensionInfo> sortedModuleExtensionInfos =
- ruleInfos.stream()
- .map(RendererMain::withSortedTagAttributes)
- .sorted(comparing(ModuleExtensionInfo::getExtensionName))
- .collect(toImmutableList());
- for (ModuleExtensionInfo moduleExtensionProto : sortedModuleExtensionInfos) {
- printWriter.println(
- renderer.render(moduleExtensionProto.getExtensionName(), moduleExtensionProto));
- printWriter.println();
- }
- }
-
private RendererMain() {}
}
diff --git a/src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java
index 52ed165..004c428 100644
--- a/src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java
+++ b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java
@@ -40,6 +40,11 @@
String headerTemplateFilePath;
@Parameter(
+ names = "--table_of_contents_template",
+ description = "The template for the table of contents string")
+ String tableOfContentsTemplateFilePath;
+
+ @Parameter(
names = "--rule_template",
required = true,
description = "The template for the documentation of a rule")
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java
index 2ff4a4e..ca07c34 100644
--- a/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java
@@ -35,11 +35,18 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.List;
/** Produces skydoc output in markdown form. */
public class MarkdownRenderer {
+
+ public interface Renderer<T> {
+ String render(T info) throws IOException;
+ }
+
// TODO(kendalllane): Refactor MarkdownRenderer to take in something other than filepaths.
private final String headerTemplateFilename;
+ private final String tableOfContentsTemplateFilename;
private final String ruleTemplateFilename;
private final String providerTemplateFilename;
private final String functionTemplateFilename;
@@ -50,6 +57,7 @@
public MarkdownRenderer(
String headerTemplate,
+ String tableOfContentsTemplateFilename,
String ruleTemplate,
String providerTemplate,
String functionTemplate,
@@ -58,6 +66,7 @@
String moduleExtensionTemplate,
String extensionBzlFile) {
this.headerTemplateFilename = headerTemplate;
+ this.tableOfContentsTemplateFilename = tableOfContentsTemplateFilename;
this.ruleTemplateFilename = ruleTemplate;
this.providerTemplateFilename = providerTemplate;
this.functionTemplateFilename = functionTemplate;
@@ -87,13 +96,48 @@
}
/**
+ * Returns a markdown string of a Table of Contents, appearing after the header and before the
+ * documentation.
+ */
+ public String renderTableOfContents(
+ List<RuleInfo> ruleInfos,
+ List<ProviderInfo> providerInfos,
+ List<StarlarkFunctionInfo> starlarkFunctions,
+ List<AspectInfo> aspectInfos,
+ List<RepositoryRuleInfo> repositoryRuleInfos,
+ List<ModuleExtensionInfo> moduleExtensionInfos)
+ throws IOException {
+
+ ImmutableMap<String, Object> vars =
+ ImmutableMap.of(
+ "util", new MarkdownUtil(extensionBzlFile),
+ "ruleInfos", ruleInfos,
+ "providerInfos", providerInfos,
+ "functionInfos", starlarkFunctions,
+ "aspectInfos", aspectInfos,
+ "repositoryRuleInfos", repositoryRuleInfos,
+ "moduleExtensionInfos", moduleExtensionInfos);
+ Reader reader = readerFromPath(tableOfContentsTemplateFilename);
+ try {
+ return Template.parseFrom(reader).evaluate(vars);
+ } catch (ParseException | EvaluationException e) {
+ throw new IOException(e);
+ }
+ }
+
+ /**
* Returns a markdown rendering of rule documentation for the given rule information object with
* the given rule name.
*/
- public String render(String ruleName, RuleInfo ruleInfo) throws IOException {
+ public String render(RuleInfo ruleInfo) throws IOException {
ImmutableMap<String, Object> vars =
ImmutableMap.of(
- "util", new MarkdownUtil(extensionBzlFile), "ruleName", ruleName, "ruleInfo", ruleInfo);
+ "util",
+ new MarkdownUtil(extensionBzlFile),
+ "ruleName",
+ ruleInfo.getRuleName(),
+ "ruleInfo",
+ ruleInfo);
Reader reader = readerFromPath(ruleTemplateFilename);
try {
return Template.parseFrom(reader).evaluate(vars);
@@ -106,13 +150,13 @@
* Returns a markdown rendering of provider documentation for the given provider information
* object with the given name.
*/
- public String render(String providerName, ProviderInfo providerInfo) throws IOException {
+ public String render(ProviderInfo providerInfo) throws IOException {
ImmutableMap<String, Object> vars =
ImmutableMap.of(
"util",
new MarkdownUtil(extensionBzlFile),
"providerName",
- providerName,
+ providerInfo.getProviderName(),
"providerInfo",
providerInfo);
Reader reader = readerFromPath(providerTemplateFilename);
@@ -142,13 +186,13 @@
* Returns a markdown rendering of aspect documentation for the given aspect information object
* with the given aspect name.
*/
- public String render(String aspectName, AspectInfo aspectInfo) throws IOException {
+ public String render(AspectInfo aspectInfo) throws IOException {
ImmutableMap<String, Object> vars =
ImmutableMap.of(
"util",
new MarkdownUtil(extensionBzlFile),
"aspectName",
- aspectName,
+ aspectInfo.getAspectName(),
"aspectInfo",
aspectInfo);
Reader reader = readerFromPath(aspectTemplateFilename);
@@ -163,14 +207,13 @@
* Returns a markdown rendering of repository rule documentation for the given repository rule
* information object with the given name.
*/
- public String render(String repositoryRuleName, RepositoryRuleInfo repositoryRuleInfo)
- throws IOException {
+ public String render(RepositoryRuleInfo repositoryRuleInfo) throws IOException {
ImmutableMap<String, Object> vars =
ImmutableMap.of(
"util",
new MarkdownUtil(extensionBzlFile),
"ruleName",
- repositoryRuleName,
+ repositoryRuleInfo.getRuleName(),
"ruleInfo",
repositoryRuleInfo);
Reader reader = readerFromPath(repositoryRuleTemplateFilename);
@@ -185,14 +228,13 @@
* Returns a markdown rendering of module extension documentation for the given module extension
* information object with the given name.
*/
- public String render(String moduleExtensionName, ModuleExtensionInfo moduleExtensionInfo)
- throws IOException {
+ public String render(ModuleExtensionInfo moduleExtensionInfo) throws IOException {
ImmutableMap<String, Object> vars =
ImmutableMap.of(
"util",
new MarkdownUtil(extensionBzlFile),
"extensionName",
- moduleExtensionName,
+ moduleExtensionInfo.getExtensionName(),
"extensionInfo",
moduleExtensionInfo);
Reader reader = readerFromPath(moduleExtensionTemplateFilename);
diff --git a/stardoc/private/stardoc.bzl b/stardoc/private/stardoc.bzl
index 16d1122..1101524 100644
--- a/stardoc/private/stardoc.bzl
+++ b/stardoc/private/stardoc.bzl
@@ -21,27 +21,33 @@
renderer_args.add("--output=" + str(ctx.outputs.out.path))
renderer_args.add("--aspect_template=" + str(ctx.file.aspect_template.path))
renderer_args.add("--header_template=" + str(ctx.file.header_template.path))
+ if ctx.attr.table_of_contents_template:
+ renderer_args.add("--table_of_contents_template=" + str(ctx.file.table_of_contents_template.path))
renderer_args.add("--func_template=" + str(ctx.file.func_template.path))
renderer_args.add("--provider_template=" + str(ctx.file.provider_template.path))
renderer_args.add("--rule_template=" + str(ctx.file.rule_template.path))
renderer_args.add("--repository_rule_template=" + str(ctx.file.repository_rule_template.path))
renderer_args.add("--module_extension_template=" + str(ctx.file.module_extension_template.path))
+
+ inputs = [
+ proto_file,
+ ctx.file.aspect_template,
+ ctx.file.header_template,
+ ctx.file.func_template,
+ ctx.file.provider_template,
+ ctx.file.rule_template,
+ ctx.file.repository_rule_template,
+ ctx.file.module_extension_template,
+ ]
+ if ctx.attr.table_of_contents_template:
+ inputs.append(ctx.file.table_of_contents_template)
renderer = ctx.executable.renderer
ctx.actions.run(
- outputs = [out_file],
- inputs = [
- proto_file,
- ctx.file.aspect_template,
- ctx.file.header_template,
- ctx.file.func_template,
- ctx.file.provider_template,
- ctx.file.rule_template,
- ctx.file.repository_rule_template,
- ctx.file.module_extension_template,
- ],
- executable = renderer,
arguments = [renderer_args],
+ executable = renderer,
+ inputs = inputs,
mnemonic = "Renderer",
+ outputs = [out_file],
progress_message = ("Converting proto format of %s to markdown format" %
(ctx.label.name)),
)
@@ -114,6 +120,14 @@
allow_single_file = [".vm"],
mandatory = True,
),
+ "table_of_contents_template": attr.label(
+ doc = "The input file template for the table of contents of the output documentation. " +
+ "This is unset by default for backwards compatibility. Use " +
+ "`Label(\"@stardoc//stardoc:templates/markdown_tables/table_of_contents.vm\")` " +
+ "for the default template.",
+ allow_single_file = [".vm"],
+ mandatory = False, # Not mandatory for backwards compatibility.
+ ),
"func_template": attr.label(
doc = "The input file template for generating documentation of functions.",
allow_single_file = [".vm"],
diff --git a/stardoc/stardoc.bzl b/stardoc/stardoc.bzl
index 06dbb97..ac312aa 100644
--- a/stardoc/stardoc.bzl
+++ b/stardoc/stardoc.bzl
@@ -32,6 +32,7 @@
aspect_template = Label("//stardoc:templates/markdown_tables/aspect.vm"),
func_template = Label("//stardoc:templates/markdown_tables/func.vm"),
header_template = Label("//stardoc:templates/markdown_tables/header.vm"),
+ table_of_contents_template = None,
provider_template = Label("//stardoc:templates/markdown_tables/provider.vm"),
rule_template = Label("//stardoc:templates/markdown_tables/rule.vm"),
repository_rule_template = Label("//stardoc:templates/markdown_tables/repository_rule.vm"),
@@ -61,6 +62,9 @@
renderer: The location of the renderer tool.
aspect_template: The input file template for generating documentation of aspects
header_template: The input file template for the header of the output documentation.
+ table_of_contents_template: The input file template for the table of contents of the output documentation.
+ This is unset by default for backwards compatibility. Use
+ `Label("@stardoc//stardoc:templates/markdown_tables/table_of_contents.vm")` for the default template.
func_template: The input file template for generating documentation of functions.
provider_template: The input file template for generating documentation of providers.
rule_template: The input file template for generating documentation of rules.
@@ -114,6 +118,7 @@
aspect_template = aspect_template,
func_template = func_template,
header_template = header_template,
+ table_of_contents_template = table_of_contents_template,
provider_template = provider_template,
rule_template = rule_template,
repository_rule_template = repository_rule_template,
diff --git a/stardoc/templates/markdown_tables/table_of_contents.vm b/stardoc/templates/markdown_tables/table_of_contents.vm
new file mode 100644
index 0000000..73d408a
--- /dev/null
+++ b/stardoc/templates/markdown_tables/table_of_contents.vm
@@ -0,0 +1,49 @@
+
+#if (!$ruleInfos.isEmpty())
+#[[##]]# Rules
+
+#foreach ($rule in $ruleInfos)
+- [$rule.ruleName](#$rule.ruleName)
+#end
+
+#end
+#if (!$providerInfos.isEmpty())
+#[[##]]# Providers
+
+#foreach ($providerInfo in $providerInfos)
+- [$providerInfo.providerName](#$providerInfo.providerName)
+#end
+
+#end
+#if (!$functionInfos.isEmpty())
+#[[##]]# Functions
+
+#foreach ($functionInfo in $functionInfos)
+- [$functionInfo.functionName](#$functionInfo.functionName)
+#end
+
+#end
+#if (!$aspectInfos.isEmpty())
+#[[##]]# Aspects
+
+#foreach ($aspectInfo in $aspectInfos)
+- [$aspectInfo.aspectName](#$aspectInfo.aspectName)
+#end
+
+#end
+#if (!$repositoryRuleInfos.isEmpty())
+#[[##]]# Repository Rules
+
+#foreach ($repositoryRuleInfo in $repositoryRuleInfos)
+- [$repositoryRuleInfo.ruleName](#$repositoryRuleInfo.ruleName)
+#end
+
+#end
+#if (!$moduleExtensionInfos.isEmpty())
+#[[##]]# Module Extensions
+
+#foreach ($moduleExtensionInfo in $moduleExtensionInfos)
+- [$moduleExtensionInfo.extensionName](#$moduleExtensionInfo.extensionName)
+#end
+
+#end
diff --git a/test/BUILD b/test/BUILD
index 3c1c284..9f151e5 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -1,3 +1,4 @@
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
load(":stardoc_test.bzl", "self_gen_test", "stardoc_test")
@@ -270,6 +271,27 @@
input_file = "testdata/config_apis_test/input.bzl",
)
+bzl_library(
+ name = "table_of_contents_test_deps",
+ srcs = [
+ "testdata/aspect_test/input.bzl",
+ "testdata/function_basic_test/input.bzl",
+ "testdata/module_extension_test/input.bzl",
+ "testdata/provider_basic_test/input.bzl",
+ "testdata/repo_rules_test/input.bzl",
+ "testdata/simple_test/input.bzl",
+ ],
+)
+
+stardoc_test(
+ name = "table_of_contents_test",
+ golden_file = "testdata/table_of_contents_test/golden.md",
+ input_file = "testdata/table_of_contents_test/input.bzl",
+ table_of_contents_template = "//stardoc:templates/markdown_tables/table_of_contents.vm",
+ test_legacy_extractor = False,
+ deps = [":table_of_contents_test_deps"],
+)
+
sh_test(
name = "local_repository_test_e2e_test",
srcs = ["diff_test_runner.sh"],
diff --git a/test/testdata/table_of_contents_test/golden.md b/test/testdata/table_of_contents_test/golden.md
new file mode 100644
index 0000000..38229b0
--- /dev/null
+++ b/test/testdata/table_of_contents_test/golden.md
@@ -0,0 +1,269 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+Test rules / providers / etc for the table of contents generation test.
+
+
+## Rules
+
+- [my_rule](#my_rule)
+
+## Providers
+
+- [MyFooInfo](#MyFooInfo)
+- [MyVeryDocumentedInfo](#MyVeryDocumentedInfo)
+
+## Functions
+
+- [check_sources](#check_sources)
+- [returns_a_thing](#returns_a_thing)
+
+## Aspects
+
+- [my_aspect](#my_aspect)
+- [other_aspect](#other_aspect)
+
+## Repository Rules
+
+- [my_repo](#my_repo)
+
+## Module Extensions
+
+- [my_ext](#my_ext)
+
+
+<a id="my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-first">first</a>, <a href="#my_rule-fourth">fourth</a>, <a href="#my_rule-second">second</a>, <a href="#my_rule-third">third</a>)
+</pre>
+
+This is my rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="my_rule-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
+| <a id="my_rule-first"></a>first | first doc string | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
+| <a id="my_rule-fourth"></a>fourth | fourth doc string | Boolean | optional | `False` |
+| <a id="my_rule-second"></a>second | - | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
+| <a id="my_rule-third"></a>third | - | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
+
+
+<a id="MyFooInfo"></a>
+
+## MyFooInfo
+
+<pre>
+MyFooInfo(<a href="#MyFooInfo-bar">bar</a>, <a href="#MyFooInfo-baz">baz</a>)
+</pre>
+
+Stores information about a foo.
+
+**FIELDS**
+
+
+| Name | Description |
+| :------------- | :------------- |
+| <a id="MyFooInfo-bar"></a>bar | - |
+| <a id="MyFooInfo-baz"></a>baz | - |
+
+
+<a id="MyVeryDocumentedInfo"></a>
+
+## MyVeryDocumentedInfo
+
+<pre>
+MyVeryDocumentedInfo(<a href="#MyVeryDocumentedInfo-favorite_food">favorite_food</a>, <a href="#MyVeryDocumentedInfo-favorite_color">favorite_color</a>)
+</pre>
+
+A provider with some really neat documentation.
+
+Look on my works, ye mighty, and despair!
+
+**FIELDS**
+
+
+| Name | Description |
+| :------------- | :------------- |
+| <a id="MyVeryDocumentedInfo-favorite_food"></a>favorite_food | A string representing my favorite food<br><br>Expected to be delicious. |
+| <a id="MyVeryDocumentedInfo-favorite_color"></a>favorite_color | A string representing my favorite color |
+
+
+<a id="check_sources"></a>
+
+## check_sources
+
+<pre>
+check_sources(<a href="#check_sources-name">name</a>, <a href="#check_sources-required_param">required_param</a>, <a href="#check_sources-bool_param">bool_param</a>, <a href="#check_sources-srcs">srcs</a>, <a href="#check_sources-string_param">string_param</a>, <a href="#check_sources-int_param">int_param</a>, <a href="#check_sources-dict_param">dict_param</a>,
+ <a href="#check_sources-struct_param">struct_param</a>)
+</pre>
+
+Runs some checks on the given source files.
+
+This rule runs checks on a given set of source files.
+Use `bazel build` to run the check.
+
+
+**PARAMETERS**
+
+
+| Name | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="check_sources-name"></a>name | A unique name for this rule. | none |
+| <a id="check_sources-required_param"></a>required_param | Use your imagination. | none |
+| <a id="check_sources-bool_param"></a>bool_param | <p align="center"> - </p> | `True` |
+| <a id="check_sources-srcs"></a>srcs | Source files to run the checks against. | `[]` |
+| <a id="check_sources-string_param"></a>string_param | <p align="center"> - </p> | `""` |
+| <a id="check_sources-int_param"></a>int_param | Your favorite number. | `2` |
+| <a id="check_sources-dict_param"></a>dict_param | <p align="center"> - </p> | `{}` |
+| <a id="check_sources-struct_param"></a>struct_param | <p align="center"> - </p> | `struct(foo = "bar")` |
+
+
+<a id="returns_a_thing"></a>
+
+## returns_a_thing
+
+<pre>
+returns_a_thing(<a href="#returns_a_thing-name">name</a>)
+</pre>
+
+Returns a suffixed name.
+
+**PARAMETERS**
+
+
+| Name | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="returns_a_thing-name"></a>name | A unique name for this rule. | none |
+
+**RETURNS**
+
+A suffixed version of the name.
+
+
+<a id="my_aspect"></a>
+
+## my_aspect
+
+<pre>
+my_aspect(<a href="#my_aspect-name">name</a>, <a href="#my_aspect-first">first</a>, <a href="#my_aspect-second">second</a>)
+</pre>
+
+This is my aspect.
+
+It does stuff.
+
+**ASPECT ATTRIBUTES**
+
+
+| Name | Type |
+| :------------- | :------------- |
+| deps| String |
+| attr_aspect| String |
+
+
+**ATTRIBUTES**
+
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="my_aspect-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
+| <a id="my_aspect-first"></a>first | - | Boolean | required | |
+| <a id="my_aspect-second"></a>second | - | String | required | |
+
+
+<a id="other_aspect"></a>
+
+## other_aspect
+
+<pre>
+other_aspect(<a href="#other_aspect-name">name</a>, <a href="#other_aspect-third">third</a>)
+</pre>
+
+This is another aspect.
+
+**ASPECT ATTRIBUTES**
+
+
+
+**ATTRIBUTES**
+
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="other_aspect-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
+| <a id="other_aspect-third"></a>third | - | Integer | required | |
+
+
+<a id="my_repo"></a>
+
+## my_repo
+
+<pre>
+my_repo(<a href="#my_repo-name">name</a>, <a href="#my_repo-repo_mapping">repo_mapping</a>, <a href="#my_repo-useless">useless</a>)
+</pre>
+
+Minimal example of a repository rule.
+
+**ATTRIBUTES**
+
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="my_repo-name"></a>name | A unique name for this repository. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
+| <a id="my_repo-repo_mapping"></a>repo_mapping | In `WORKSPACE` context only: a dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.<br><br>For example, an entry `"@foo": "@bar"` declares that, for any time this repository depends on `@foo` (such as a dependency on `@foo//some:target`, it should actually resolve that dependency within globally-declared `@bar` (`@bar//some:target`).<br><br>This attribute is _not_ supported in `MODULE.bazel` context (when invoking a repository rule inside a module extension's implementation function). | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | |
+| <a id="my_repo-useless"></a>useless | This argument will be ignored.<br><br>You don't have to specify it, but you may. | String | optional | `"ignoreme"` |
+
+**ENVIRONMENT VARIABLES**
+
+This repository rule depends on the following environment variables:
+
+* `FOO_CC`
+* `BAR_PATH`
+
+
+<a id="my_ext"></a>
+
+## my_ext
+
+<pre>
+my_ext = use_extension("@io_bazel_stardoc//test:testdata/table_of_contents_test/input.bzl", "my_ext")
+my_ext.install(<a href="#my_ext.install-artifacts">artifacts</a>)
+my_ext.artifact(<a href="#my_ext.artifact-artifact">artifact</a>, <a href="#my_ext.artifact-group">group</a>)
+</pre>
+
+Minimal example of a module extension.
+
+
+**TAG CLASSES**
+
+<a id="my_ext.install"></a>
+
+### install
+
+Install tag
+
+**Attributes**
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="my_ext.install-artifacts"></a>artifacts | Install artifacts | List of strings | optional | `[]` |
+
+<a id="my_ext.artifact"></a>
+
+### artifact
+
+Artifact tag
+
+**Attributes**
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="my_ext.artifact-artifact"></a>artifact | Artifact | String | required | |
+| <a id="my_ext.artifact-group"></a>group | Group name | String | optional | `"my_group"` |
+
+
diff --git a/test/testdata/table_of_contents_test/input.bzl b/test/testdata/table_of_contents_test/input.bzl
new file mode 100644
index 0000000..5d034b4
--- /dev/null
+++ b/test/testdata/table_of_contents_test/input.bzl
@@ -0,0 +1,26 @@
+"""Test rules / providers / etc for the table of contents generation test."""
+
+load("//test:testdata/aspect_test/input.bzl", _my_aspect = "my_aspect", _other_aspect = "other_aspect")
+load("//test:testdata/function_basic_test/input.bzl", _check_sources = "check_sources", _returns_a_thing = "returns_a_thing")
+load("//test:testdata/module_extension_test/input.bzl", _my_ext = "my_ext")
+load("//test:testdata/provider_basic_test/input.bzl", _MyFooInfo = "MyFooInfo", _MyVeryDocumentedInfo = "MyVeryDocumentedInfo")
+load("//test:testdata/repo_rules_test/input.bzl", _my_repo = "my_repo")
+load("//test:testdata/simple_test/input.bzl", _my_rule = "my_rule")
+
+my_rule = _my_rule
+
+MyFooInfo = _MyFooInfo
+
+MyVeryDocumentedInfo = _MyVeryDocumentedInfo
+
+check_sources = _check_sources
+
+returns_a_thing = _returns_a_thing
+
+my_aspect = _my_aspect
+
+other_aspect = _other_aspect
+
+my_repo = _my_repo
+
+my_ext = _my_ext