Move the markdown renderer from Bazel repo into Stardoc repo (#162)
Moving from https://github.com/bazelbuild/bazel/tree/3d2604806a9747f317c5b560bbf89cdc1be033ba
* src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java and src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java have been changed to use JCommander instead of Bazel's options library for command-line arg parsing. All other .java files have been copied from Bazel without any changes and without any file/directory renames.
* integration tests from src/test/java/com/google/devtools/build/skydoc/testdata in Bazel have been merged into tests/testdata in Stardoc where appropriate (filter_rules_test, function_basic_test, function_wrap_multiple_lines_test, multi_level_namespace_test_with_allowlist, provider_basic_test, pure_markdown_template_test, repo_rules_test)
* updated Stardoc's deps and to allow building the renderer. In particular, we now are forced to depend on rules_jvm_external unconditionally, even in releases.
* removed renderer_binary.jar
diff --git a/BUILD b/BUILD
index a9859d7..85e0841 100644
--- a/BUILD
+++ b/BUILD
@@ -32,6 +32,11 @@
"CONTRIBUTORS",
"LICENSE",
"MODULE.bazel",
+ "maven_install.json",
+ "rules_jvm_external.patch",
+ "//src/main/java/com/google/devtools/build/skydoc/renderer:srcs",
+ "//src/main/java/com/google/devtools/build/skydoc/rendering:srcs",
+ "//src/test/java/com/google/devtools/build/skydoc/rendering:srcs",
"//stardoc:distro_srcs",
"//stardoc/private:distro_srcs",
"//stardoc/proto:distro_srcs",
diff --git a/MODULE.bazel b/MODULE.bazel
index 521a1a9..98866ac 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -5,5 +5,18 @@
)
bazel_dep(name = "bazel_skylib", version = "1.2.1")
-bazel_dep(name = "rules_java", version = "6.0.0")
-bazel_dep(name = "rules_license", version = "0.0.3")
+bazel_dep(name = "rules_java", version = "6.1.1")
+bazel_dep(name = "rules_jvm_external", version = "4.5")
+bazel_dep(name = "rules_license", version = "0.0.7")
+bazel_dep(name = "protobuf", version = "21.7", repo_name = "com_google_protobuf")
+
+maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
+maven.install(
+ # We don't yet specify the maven coordinates in the MODULE.bazel to avoid duplicating information.
+ # Always respect the maven_install.json file generated by rules_jvm_external from the WORKSPACE file.
+ lock_file = "//:maven_install.json",
+ repositories = [
+ "https://repo1.maven.org/maven2",
+ ],
+)
+use_repo(maven, "maven")
diff --git a/WORKSPACE b/WORKSPACE
index 2191a2c..f2a36f7 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -5,6 +5,88 @@
stardoc_repositories()
+RULES_JVM_EXTERNAL_TAG = "4.5"
+
+RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6"
+
+http_archive(
+ name = "rules_jvm_external",
+ patch_args = ["-p1"],
+ patches = ["//:rules_jvm_external.patch"],
+ sha256 = RULES_JVM_EXTERNAL_SHA,
+ strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
+ url = "https://github.com/bazelbuild/rules_jvm_external/archive/refs/tags/%s.zip" % RULES_JVM_EXTERNAL_TAG,
+)
+
+load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
+
+rules_jvm_external_deps()
+
+load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
+
+rules_jvm_external_setup()
+
+load("@rules_jvm_external//:defs.bzl", "maven_install")
+
+maven_install(
+ artifacts = [
+ "com.beust:jcommander:1.82",
+ "com.google.guava:guava:31.1-jre",
+ "com.google.truth:truth:1.1.3",
+ "org.apache.velocity:velocity:1.7",
+ "junit:junit:4.13.2",
+ # Artifacts below this line are only needed for building @io_bazel for
+ # stardoc_binary.jar integration tests. They should be removed once we
+ # fully migrate to starlark_doc_extract after Bazel 7.
+ "com.github.ben-manes.caffeine:caffeine:3.0.5",
+ "com.github.stephenc.jcip:jcip-annotations:1.0-1",
+ "com.google.auto.service:auto-service-annotations:1.0.1",
+ "com.google.auto.service:auto-service:1.0",
+ "com.google.auto.value:auto-value-annotations:1.9",
+ "com.google.auto.value:auto-value:1.8.2",
+ "com.google.auto:auto-common:1.2.1",
+ "com.google.code.findbugs:jsr305:3.0.2",
+ "com.google.code.gson:gson:2.9.0",
+ "com.google.errorprone:error_prone_annotations:2.18.0",
+ "com.google.errorprone:error_prone_type_annotations:2.18.0",
+ "com.google.flogger:flogger-system-backend:0.5.1",
+ "com.google.flogger:flogger:0.5.1",
+ "com.google.flogger:google-extensions:0.5.1",
+ "com.google.guava:failureaccess:1.0.1",
+ "com.google.j2objc:j2objc-annotations:1.3",
+ "com.ryanharter.auto.value:auto-value-gson-extension:1.3.1",
+ "com.ryanharter.auto.value:auto-value-gson-runtime:1.3.1",
+ "com.ryanharter.auto.value:auto-value-gson-factory:1.3.1",
+ "com.squareup:javapoet:1.12.0",
+ "commons-collections:commons-collections:3.2.2",
+ "commons-lang:commons-lang:2.6",
+ "org.apache.tomcat:tomcat-annotations-api:8.0.5",
+ "org.checkerframework:checker-qual:3.19.0",
+ ],
+ fail_if_repin_required = True,
+ maven_install_json = "//:maven_install.json",
+ repositories = [
+ "https://repo1.maven.org/maven2",
+ ],
+ strict_visibility = True,
+)
+
+load("@maven//:defs.bzl", "pinned_maven_install")
+
+pinned_maven_install()
+
+http_archive(
+ name = "com_google_protobuf",
+ sha256 = "75be42bd736f4df6d702a0e4e4d30de9ee40eac024c4b845d17ae4cc831fe4ae",
+ strip_prefix = "protobuf-21.7",
+ urls = [
+ "https://mirror.bazel.build/github.com/protocolbuffers/protobuf/archive/v21.7.tar.gz",
+ "https://github.com/protocolbuffers/protobuf/archive/v21.7.tar.gz",
+ ],
+)
+
+load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
+
### INTERNAL ONLY - lines after this are not included in the release packaging.
#
# Include dependencies which are only needed for development of Stardoc here.
@@ -34,70 +116,6 @@
actual = "@io_bazel//third_party:error_prone_annotations",
)
-RULES_JVM_EXTERNAL_TAG = "4.5"
-
-RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6"
-
-http_archive(
- name = "rules_jvm_external",
- patch_args = ["-p1"],
- patches = ["//:rules_jvm_external.patch"],
- sha256 = RULES_JVM_EXTERNAL_SHA,
- strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
- url = "https://github.com/bazelbuild/rules_jvm_external/archive/refs/tags/%s.zip" % RULES_JVM_EXTERNAL_TAG,
-)
-
-load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
-
-rules_jvm_external_deps()
-
-load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
-
-rules_jvm_external_setup()
-
-load("@rules_jvm_external//:defs.bzl", "maven_install")
-
-maven_install(
- artifacts = [
- "com.github.ben-manes.caffeine:caffeine:3.0.5",
- "com.github.stephenc.jcip:jcip-annotations:1.0-1",
- "com.google.auto.service:auto-service-annotations:1.0.1",
- "com.google.auto.service:auto-service:1.0",
- "com.google.auto.value:auto-value-annotations:1.9",
- "com.google.auto.value:auto-value:1.8.2",
- "com.google.auto:auto-common:1.2.1",
- "com.google.code.findbugs:jsr305:3.0.2",
- "com.google.code.gson:gson:2.9.0",
- "com.google.errorprone:error_prone_annotations:2.18.0",
- "com.google.errorprone:error_prone_type_annotations:2.18.0",
- "com.google.flogger:flogger-system-backend:0.5.1",
- "com.google.flogger:flogger:0.5.1",
- "com.google.flogger:google-extensions:0.5.1",
- "com.google.guava:failureaccess:1.0.1",
- "com.google.guava:guava:31.1-jre",
- "com.google.j2objc:j2objc-annotations:1.3",
- "com.ryanharter.auto.value:auto-value-gson-extension:1.3.1",
- "com.ryanharter.auto.value:auto-value-gson-runtime:1.3.1",
- "com.ryanharter.auto.value:auto-value-gson-factory:1.3.1",
- "com.squareup:javapoet:1.12.0",
- "commons-collections:commons-collections:3.2.2",
- "commons-lang:commons-lang:2.6",
- "org.apache.tomcat:tomcat-annotations-api:8.0.5",
- "org.apache.velocity:velocity:1.7",
- "org.checkerframework:checker-qual:3.19.0",
- ],
- fail_if_repin_required = True,
- maven_install_json = "//:maven_install.json",
- repositories = [
- "https://repo1.maven.org/maven2",
- ],
- strict_visibility = True,
-)
-
-load("@maven//:defs.bzl", "pinned_maven_install")
-
-pinned_maven_install()
-
# Needed only because of java_tools.
http_archive(
name = "rules_cc",
@@ -152,3 +170,7 @@
rules_proto_dependencies()
rules_proto_toolchains()
+
+### END INTERNAL ONLY
+# protobuf_deps() must not be called before @rules_python are loaded (if they are loaded).
+protobuf_deps()
diff --git a/distro/BUILD b/distro/BUILD
index 84a670e..4fc0e1c 100644
--- a/distro/BUILD
+++ b/distro/BUILD
@@ -15,7 +15,7 @@
name = "distro_workspace",
srcs = ["//:WORKSPACE"],
outs = ["WORKSPACE"],
- cmd = "sed -e '/### INTERNAL ONLY/,$$d' $(location //:WORKSPACE) >$@",
+ cmd = "sed -e '/### INTERNAL ONLY/,/### END INTERNAL ONLY/d' $(location //:WORKSPACE) >$@",
)
pkg_tar(
diff --git a/docs/maintainers_guide.md b/docs/maintainers_guide.md
index c4358cc..fabd533 100644
--- a/docs/maintainers_guide.md
+++ b/docs/maintainers_guide.md
@@ -1,15 +1,14 @@
# Stardoc Maintainer's Guide
-## Updating Jars
+## Updating Bundled Jar
Stardoc's source code currently lives in the Bazel source tree at
https://github.com/bazelbuild/bazel/tree/master/src/main/java/com/google/devtools/build/skydoc
-For simplicity of use and building, Stardoc bundles two pre-built jars built
-from Bazel source: `stardoc_binary.jar` (emits protobuf documentation format)
-and `renderer_binary.jar` (turns the protobuf into markdown).
+For simplicity of use and building, Stardoc bundles a pre-built jar built
+from Bazel source: `stardoc_binary.jar` (emits protobuf documentation format).
-To update the jars:
+To update the jar:
1. Update `io_bazel` repo commit in `WORKSPACE`. Update transitive deps in
`WORKSPACE` as needed.
diff --git a/maven_install.json b/maven_install.json
index 0ff1d50..0ed8554 100644
--- a/maven_install.json
+++ b/maven_install.json
@@ -1,11 +1,31 @@
{
"dependency_tree": {
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
- "__INPUT_ARTIFACTS_HASH": 1429940565,
- "__RESOLVED_ARTIFACTS_HASH": 1065334191,
+ "__INPUT_ARTIFACTS_HASH": -568257785,
+ "__RESOLVED_ARTIFACTS_HASH": -1924638958,
"conflict_resolution": {},
"dependencies": [
{
+ "coord": "com.beust:jcommander:1.82",
+ "dependencies": [],
+ "directDependencies": [],
+ "file": "v1/https/repo1.maven.org/maven2/com/beust/jcommander/1.82/jcommander-1.82.jar",
+ "mirror_urls": [
+ "https://repo1.maven.org/maven2/com/beust/jcommander/1.82/jcommander-1.82.jar"
+ ],
+ "packages": [
+ "com.beust.ah",
+ "com.beust.jcommander",
+ "com.beust.jcommander.converters",
+ "com.beust.jcommander.defaultprovider",
+ "com.beust.jcommander.internal",
+ "com.beust.jcommander.parser",
+ "com.beust.jcommander.validators"
+ ],
+ "sha256": "deeac157c8de6822878d85d0c7bc8467a19cc8484d37788f7804f039dde280b1",
+ "url": "https://repo1.maven.org/maven2/com/beust/jcommander/1.82/jcommander-1.82.jar"
+ },
+ {
"coord": "com.github.ben-manes.caffeine:caffeine:3.0.5",
"dependencies": [
"com.google.errorprone:error_prone_annotations:2.18.0",
@@ -367,6 +387,35 @@
"url": "https://repo1.maven.org/maven2/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar"
},
{
+ "coord": "com.google.truth:truth:1.1.3",
+ "dependencies": [
+ "com.google.auto.value:auto-value-annotations:1.9",
+ "com.google.errorprone:error_prone_annotations:2.18.0",
+ "com.google.guava:guava:31.1-jre",
+ "junit:junit:4.13.2",
+ "org.checkerframework:checker-qual:3.19.0",
+ "org.hamcrest:hamcrest-core:1.3",
+ "org.ow2.asm:asm:9.1"
+ ],
+ "directDependencies": [
+ "com.google.auto.value:auto-value-annotations:1.9",
+ "com.google.errorprone:error_prone_annotations:2.18.0",
+ "com.google.guava:guava:31.1-jre",
+ "junit:junit:4.13.2",
+ "org.checkerframework:checker-qual:3.19.0",
+ "org.ow2.asm:asm:9.1"
+ ],
+ "file": "v1/https/repo1.maven.org/maven2/com/google/truth/truth/1.1.3/truth-1.1.3.jar",
+ "mirror_urls": [
+ "https://repo1.maven.org/maven2/com/google/truth/truth/1.1.3/truth-1.1.3.jar"
+ ],
+ "packages": [
+ "com.google.common.truth"
+ ],
+ "sha256": "fc0b67782289a2aabfddfdf99eff1dcd5edc890d49143fcd489214b107b8f4f3",
+ "url": "https://repo1.maven.org/maven2/com/google/truth/truth/1.1.3/truth-1.1.3.jar"
+ },
+ {
"coord": "com.ryanharter.auto.value:auto-value-gson-extension:1.3.1",
"dependencies": [
"com.google.auto.value:auto-value-annotations:1.9",
@@ -552,6 +601,55 @@
"url": "https://repo1.maven.org/maven2/io/sweers/autotransient/autotransient/1.0.0/autotransient-1.0.0.jar"
},
{
+ "coord": "junit:junit:4.13.2",
+ "dependencies": [
+ "org.hamcrest:hamcrest-core:1.3"
+ ],
+ "directDependencies": [
+ "org.hamcrest:hamcrest-core:1.3"
+ ],
+ "file": "v1/https/repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar",
+ "mirror_urls": [
+ "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar"
+ ],
+ "packages": [
+ "junit.extensions",
+ "junit.framework",
+ "junit.runner",
+ "junit.textui",
+ "org.junit",
+ "org.junit.experimental",
+ "org.junit.experimental.categories",
+ "org.junit.experimental.max",
+ "org.junit.experimental.results",
+ "org.junit.experimental.runners",
+ "org.junit.experimental.theories",
+ "org.junit.experimental.theories.internal",
+ "org.junit.experimental.theories.suppliers",
+ "org.junit.function",
+ "org.junit.internal",
+ "org.junit.internal.builders",
+ "org.junit.internal.management",
+ "org.junit.internal.matchers",
+ "org.junit.internal.requests",
+ "org.junit.internal.runners",
+ "org.junit.internal.runners.model",
+ "org.junit.internal.runners.rules",
+ "org.junit.internal.runners.statements",
+ "org.junit.matchers",
+ "org.junit.rules",
+ "org.junit.runner",
+ "org.junit.runner.manipulation",
+ "org.junit.runner.notification",
+ "org.junit.runners",
+ "org.junit.runners.model",
+ "org.junit.runners.parameterized",
+ "org.junit.validator"
+ ],
+ "sha256": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3",
+ "url": "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar"
+ },
+ {
"coord": "org.apache.tomcat:tomcat-annotations-api:8.0.5",
"dependencies": [],
"directDependencies": [],
@@ -670,6 +768,37 @@
],
"sha256": "a827c49183f3a632277d27a0a4673686cb341507447b9d570261094bd748aa68",
"url": "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.19.0/checker-qual-3.19.0.jar"
+ },
+ {
+ "coord": "org.hamcrest:hamcrest-core:1.3",
+ "dependencies": [],
+ "directDependencies": [],
+ "file": "v1/https/repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar",
+ "mirror_urls": [
+ "https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar"
+ ],
+ "packages": [
+ "org.hamcrest",
+ "org.hamcrest.core",
+ "org.hamcrest.internal"
+ ],
+ "sha256": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9",
+ "url": "https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar"
+ },
+ {
+ "coord": "org.ow2.asm:asm:9.1",
+ "dependencies": [],
+ "directDependencies": [],
+ "file": "v1/https/repo1.maven.org/maven2/org/ow2/asm/asm/9.1/asm-9.1.jar",
+ "mirror_urls": [
+ "https://repo1.maven.org/maven2/org/ow2/asm/asm/9.1/asm-9.1.jar"
+ ],
+ "packages": [
+ "org.objectweb.asm",
+ "org.objectweb.asm.signature"
+ ],
+ "sha256": "cda4de455fab48ff0bcb7c48b4639447d4de859a7afc30a094a986f0936beba2",
+ "url": "https://repo1.maven.org/maven2/org/ow2/asm/asm/9.1/asm-9.1.jar"
}
],
"version": "0.1.0"
diff --git a/setup.bzl b/setup.bzl
index 720c5ce..9797de6 100644
--- a/setup.bzl
+++ b/setup.bzl
@@ -35,18 +35,17 @@
http_archive,
name = "rules_java",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_java/releases/download/6.0.0/rules_java-6.0.0.tar.gz",
- "https://github.com/bazelbuild/rules_java/releases/download/6.0.0/rules_java-6.0.0.tar.gz",
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_java/releases/download/6.1.1/rules_java-6.1.1.tar.gz",
+ "https://github.com/bazelbuild/rules_java/releases/download/6.1.1/rules_java-6.1.1.tar.gz",
],
- sha256 = "469b7f3b580b4fcf8112f4d6d0d5a4ce8e1ad5e21fee67d8e8335d5f8b3debab",
+ sha256 = "76402a50ae6859d50bd7aed8c1b8ef09dae5c1035bb3ca7d276f7f3ce659818a",
)
_include_if_not_defined(
http_archive,
name = "rules_license",
- # TODO: Bazel@HEAD fails in the analysis phase with rules_license 0.0.4.
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.3/rules_license-0.0.3.tar.gz",
- "https://github.com/bazelbuild/rules_license/releases/download/0.0.3/rules_license-0.0.3.tar.gz",
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz",
+ "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz",
],
- sha256 = "00ccc0df21312c127ac4b12880ab0f9a26c1cff99442dc6c5a331750360de3c3",
+ sha256 = "4531deccb913639c30e5c7512a054d5d875698daeb75d8cf90f284375fe7c360",
)
diff --git a/src/main/java/com/google/devtools/build/skydoc/renderer/BUILD b/src/main/java/com/google/devtools/build/skydoc/renderer/BUILD
new file mode 100644
index 0000000..db17567
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/renderer/BUILD
@@ -0,0 +1,45 @@
+load("@rules_java//java:defs.bzl", "java_binary", "java_library")
+
+package(
+ default_applicable_licenses = ["//:license"],
+ default_visibility = [
+ "//src:__subpackages__",
+ "//stardoc:__subpackages__",
+ ],
+)
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+ visibility = ["//:__pkg__"],
+)
+
+java_binary(
+ name = "renderer",
+ jvm_flags = [
+ # quiet warnings from com.google.protobuf.UnsafeUtil,
+ # see: https://github.com/google/protobuf/issues/3781
+ # and: https://github.com/bazelbuild/bazel/issues/5599
+ "--add-opens=java.base/java.nio=ALL-UNNAMED",
+ "--add-opens=java.base/java.lang=ALL-UNNAMED",
+ # ... but only on JDK >= 9
+ "-XX:+IgnoreUnrecognizedVMOptions",
+ ],
+ main_class = "com.google.devtools.build.skydoc.renderer.RendererMain",
+ visibility = ["//visibility:public"],
+ runtime_deps = [
+ ":renderer_lib",
+ ],
+)
+
+java_library(
+ name = "renderer_lib",
+ srcs = glob(["*.java"]),
+ deps = [
+ "//src/main/java/com/google/devtools/build/skydoc/rendering",
+ "//stardoc/proto:stardoc_output_java_proto",
+ "@com_google_protobuf//:protobuf_java",
+ "@maven//:com_beust_jcommander",
+ "@maven//:com_google_guava_guava",
+ ],
+)
diff --git a/src/main/java/com/google/devtools/build/skydoc/renderer/FileSystemAccessor.java b/src/main/java/com/google/devtools/build/skydoc/renderer/FileSystemAccessor.java
new file mode 100644
index 0000000..3e424d8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/renderer/FileSystemAccessor.java
@@ -0,0 +1,45 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.skydoc.renderer;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/** Implementation of {@link ProtoFileAccessor} which uses the real filesystem. */
+public class FileSystemAccessor implements ProtoFileAccessor {
+
+ @Override
+ public byte[] getProtoContent(String inputPathString) throws IOException {
+ Path inputPath = Paths.get(inputPathString);
+ byte[] inputContent = Files.readAllBytes(inputPath);
+ return inputContent;
+ }
+
+ @Override
+ public boolean fileExists(String pathString) {
+ return Files.exists(Paths.get(pathString));
+ }
+
+ @Override
+ public void writeToOutputLocation(String outputPathString, byte[] content) throws IOException {
+ try (FileOutputStream outputStream = new FileOutputStream(outputPathString)) {
+ for (byte byteContent : content) {
+ outputStream.write(byteContent);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/renderer/ProtoFileAccessor.java b/src/main/java/com/google/devtools/build/skydoc/renderer/ProtoFileAccessor.java
new file mode 100644
index 0000000..3b75d9b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/renderer/ProtoFileAccessor.java
@@ -0,0 +1,42 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.skydoc.renderer;
+
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Helper to handle Proto file I/O. This abstraction is useful for tests which don't involve actual
+ * file I/O.
+ */
+public interface ProtoFileAccessor {
+ /**
+ * Returns the bytes from the raw proto file.
+ *
+ * @param inputPathString the path of the input raw {@link StardocOutputProtos} file.
+ */
+ byte[] getProtoContent(String inputPathString) throws IOException;
+
+ /** Returns true if a file exists at the current path. */
+ boolean fileExists(String pathString);
+
+ /**
+ * Creates a {@link FileOutputStream} and writes the bytes to the output location.
+ *
+ * @param outputPathString the output location that is being written to
+ * @param content the bytes from input proto file
+ */
+ void writeToOutputLocation(String outputPathString, byte[] content) throws IOException;
+}
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
new file mode 100644
index 0000000..55cdd84
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererMain.java
@@ -0,0 +1,184 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.skydoc.renderer;
+
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Comparator.comparing;
+
+import com.beust.jcommander.JCommander;
+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.proto.StardocOutputProtos.AspectInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.AttributeInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ModuleInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ProviderInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.RuleInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.StarlarkFunctionInfo;
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Main entry point for Renderer binary.
+ *
+ * <p>This Renderer takes in raw stardoc_proto protos as input and produces rich markdown output.
+ */
+public class RendererMain {
+
+ public static void main(String[] args) throws IOException {
+
+ RendererOptions rendererOptions = new RendererOptions();
+ JCommander jcommander =
+ JCommander.newBuilder().addObject(rendererOptions).build();
+ jcommander.setProgramName("renderer");
+ jcommander.parse(args);
+ if (rendererOptions.printHelp) {
+ jcommander.usage();
+ return;
+ }
+
+ String inputPath = rendererOptions.inputPath;
+ String outputPath = rendererOptions.outputFilePath;
+ String headerTemplatePath = rendererOptions.headerTemplateFilePath;
+ String ruleTemplatePath = rendererOptions.ruleTemplateFilePath;
+ String providerTemplatePath = rendererOptions.providerTemplateFilePath;
+ String funcTemplatePath = rendererOptions.funcTemplateFilePath;
+ String aspectTemplatePath = rendererOptions.aspectTemplateFilePath;
+
+ MarkdownRenderer renderer =
+ new MarkdownRenderer(
+ headerTemplatePath,
+ ruleTemplatePath,
+ providerTemplatePath,
+ funcTemplatePath,
+ aspectTemplatePath);
+ try (PrintWriter printWriter =
+ new PrintWriter(outputPath, UTF_8) {
+ // Use consistent line endings on all platforms.
+ @Override
+ public void println() {
+ write("\n");
+ }
+ }) {
+ ModuleInfo moduleInfo = ModuleInfo.parseFrom(new FileInputStream(inputPath));
+ 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());
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalArgumentException("Input file is not a valid ModuleInfo proto.", e);
+ }
+ }
+
+ // 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 =
+ ImmutableMap.<String, Integer>builder()
+ .put("name", -99)
+ .put("deps", -98)
+ .put("src", -97)
+ .put("srcs", -96)
+ .put("data", -95)
+ .put("resource", -94)
+ .put("resources", -93)
+ .put("out", -92)
+ .put("outs", -91)
+ .put("hdrs", -90)
+ .buildOrThrow();
+
+ private static final Comparator<String> ATTRIBUTE_NAME_COMPARATOR =
+ (a, b) -> {
+ int aOrdering = ATTRIBUTE_ORDERING.getOrDefault(a, 0);
+ int bOrdering = ATTRIBUTE_ORDERING.getOrDefault(b, 0);
+ if (aOrdering > bOrdering) {
+ return 1;
+ } else if (aOrdering < bOrdering) {
+ return -1;
+ } else {
+ return Comparator.<String>naturalOrder().compare(a, b);
+ }
+ };
+
+ private static RuleInfo withSortedRuleAttributes(RuleInfo ruleInfo) {
+ return ruleInfo.toBuilder()
+ .clearAttribute()
+ .addAllAttribute(
+ ImmutableList.sortedCopyOf(
+ comparing(AttributeInfo::getName, ATTRIBUTE_NAME_COMPARATOR),
+ ruleInfo.getAttributeList()))
+ .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();
+ }
+ }
+}
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
new file mode 100644
index 0000000..5abef40
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/renderer/RendererOptions.java
@@ -0,0 +1,71 @@
+// Copyright 2023 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.skydoc.renderer;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+/** Contains options for running {@link RendererMain}. */
+@Parameters(separators = "=")
+class RendererOptions {
+
+ @Parameter(
+ names = "--input",
+ required = true,
+ description = "The path of the proto file that will be converted to markdown")
+ String inputPath;
+
+ @Parameter(
+ names = "--output",
+ required = true,
+ description = "The path of the file to output documentation into")
+ String outputFilePath;
+
+ @Parameter(
+ names = "--header_template",
+ required = true,
+ description = "The template for the header string")
+ String headerTemplateFilePath;
+
+ @Parameter(
+ names = "--rule_template",
+ required = true,
+ description = "The template for the documentation of a rule")
+ String ruleTemplateFilePath;
+
+ @Parameter(
+ names = "--provider_template",
+ required = true,
+ description = "The template for the documentation of a provider")
+ String providerTemplateFilePath;
+
+ @Parameter(
+ names = "--func_template",
+ required = true,
+ description = "The template for the documentation of a function")
+ String funcTemplateFilePath;
+
+ @Parameter(
+ names = "--aspect_template",
+ required = true,
+ description = "The template for the documentation of an aspect")
+ String aspectTemplateFilePath;
+
+ @Parameter(
+ names = {"--help", "-h"},
+ description = "Print help and exit",
+ help = true)
+ boolean printHelp;
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD b/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD
new file mode 100644
index 0000000..92c9021
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD
@@ -0,0 +1,27 @@
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(
+ default_applicable_licenses = ["//:license"],
+ default_visibility = [
+ "//src:__subpackages__",
+ "//stardoc:__subpackages__",
+ ],
+)
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+ visibility = ["//:__pkg__"],
+)
+
+java_library(
+ name = "rendering",
+ srcs = glob(
+ ["*.java"],
+ ),
+ deps = [
+ "//stardoc/proto:stardoc_output_java_proto",
+ "@maven//:com_google_guava_guava",
+ "@maven//:org_apache_velocity_velocity",
+ ],
+)
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
new file mode 100644
index 0000000..3a2085c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java
@@ -0,0 +1,191 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.skydoc.rendering;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.AspectInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ModuleInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ProviderInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.RuleInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.StarlarkFunctionInfo;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.apache.velocity.runtime.resource.loader.JarResourceLoader;
+
+/** Produces skydoc output in markdown form. */
+public class MarkdownRenderer {
+ // TODO(kendalllane): Refactor MarkdownRenderer to take in something other than filepaths.
+ private final String headerTemplateFilename;
+ private final String ruleTemplateFilename;
+ private final String providerTemplateFilename;
+ private final String functionTemplateFilename;
+ private final String aspectTemplateFilename;
+
+ private final VelocityEngine velocityEngine;
+
+ public MarkdownRenderer(
+ String headerTemplate,
+ String ruleTemplate,
+ String providerTemplate,
+ String functionTemplate,
+ String aspectTemplate) {
+ this.headerTemplateFilename = headerTemplate;
+ this.ruleTemplateFilename = ruleTemplate;
+ this.providerTemplateFilename = providerTemplate;
+ this.functionTemplateFilename = functionTemplate;
+ this.aspectTemplateFilename = aspectTemplate;
+
+ this.velocityEngine = new VelocityEngine();
+ velocityEngine.setProperty("resource.loader", "classpath, jar");
+ velocityEngine.setProperty(
+ "classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
+ velocityEngine.setProperty("jar.resource.loader.class", JarResourceLoader.class.getName());
+ velocityEngine.setProperty("input.encoding", "UTF-8");
+ velocityEngine.setProperty("output.encoding", "UTF-8");
+ velocityEngine.setProperty("runtime.references.strict", true);
+
+ // Ensure formatting is the same on Velocity 1.7 and 2.x.
+ velocityEngine.setProperty("parser.space_gobbling", "bc");
+ }
+
+ /**
+ * Returns a markdown header string that should appear at the top of Stardoc's output, providing a
+ * summary for the input Starlark module.
+ */
+ public String renderMarkdownHeader(ModuleInfo moduleInfo) throws IOException {
+ VelocityContext context = new VelocityContext();
+ context.put("util", new MarkdownUtil());
+ context.put("moduleDocstring", moduleInfo.getModuleDocstring());
+
+ StringWriter stringWriter = new StringWriter();
+ Reader reader = readerFromPath(headerTemplateFilename);
+ try {
+ velocityEngine.evaluate(context, stringWriter, headerTemplateFilename, reader);
+ } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) {
+ throw new IOException(e);
+ }
+ return stringWriter.toString();
+ }
+
+ /**
+ * 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 {
+ VelocityContext context = new VelocityContext();
+ context.put("util", new MarkdownUtil());
+ context.put("ruleName", ruleName);
+ context.put("ruleInfo", ruleInfo);
+
+ StringWriter stringWriter = new StringWriter();
+ Reader reader = readerFromPath(ruleTemplateFilename);
+ try {
+ velocityEngine.evaluate(context, stringWriter, ruleTemplateFilename, reader);
+ } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) {
+ throw new IOException(e);
+ }
+ return stringWriter.toString();
+ }
+
+ /**
+ * 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 {
+ VelocityContext context = new VelocityContext();
+ context.put("util", new MarkdownUtil());
+ context.put("providerName", providerName);
+ context.put("providerInfo", providerInfo);
+
+ StringWriter stringWriter = new StringWriter();
+ Reader reader = readerFromPath(providerTemplateFilename);
+ try {
+ velocityEngine.evaluate(context, stringWriter, providerTemplateFilename, reader);
+ } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) {
+ throw new IOException(e);
+ }
+ return stringWriter.toString();
+ }
+
+ /**
+ * Returns a markdown rendering of a user-defined function's documentation for the function info
+ * object.
+ */
+ public String render(StarlarkFunctionInfo functionInfo) throws IOException {
+ VelocityContext context = new VelocityContext();
+ context.put("util", new MarkdownUtil());
+ context.put("funcInfo", functionInfo);
+
+ StringWriter stringWriter = new StringWriter();
+ Reader reader = readerFromPath(functionTemplateFilename);
+ try {
+ velocityEngine.evaluate(context, stringWriter, functionTemplateFilename, reader);
+ } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) {
+ throw new IOException(e);
+ }
+ return stringWriter.toString();
+ }
+
+ /**
+ * 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 {
+ VelocityContext context = new VelocityContext();
+ context.put("util", new MarkdownUtil());
+ context.put("aspectName", aspectName);
+ context.put("aspectInfo", aspectInfo);
+
+ StringWriter stringWriter = new StringWriter();
+ Reader reader = readerFromPath(aspectTemplateFilename);
+ try {
+ velocityEngine.evaluate(context, stringWriter, aspectTemplateFilename, reader);
+ } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) {
+ throw new IOException(e);
+ }
+ return stringWriter.toString();
+ }
+ /**
+ * Returns a reader from the given path.
+ *
+ * @param filePath The given path, either a filesystem path or a java Resource
+ */
+ private static Reader readerFromPath(String filePath) throws IOException {
+ if (Files.exists(Paths.get(filePath))) {
+ Path path = Paths.get(filePath);
+ return Files.newBufferedReader(path);
+ }
+
+ InputStream inputStream = MarkdownRenderer.class.getClassLoader().getResourceAsStream(filePath);
+ if (inputStream == null) {
+ throw new FileNotFoundException(filePath + " was not found as a resource.");
+ }
+ return new InputStreamReader(inputStream, UTF_8);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownUtil.java b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownUtil.java
new file mode 100644
index 0000000..4dd6310
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownUtil.java
@@ -0,0 +1,307 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.skydoc.rendering;
+
+import static java.util.Comparator.naturalOrder;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+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.AttributeType;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.FunctionParamInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ProviderInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ProviderNameGroup;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.RuleInfo;
+import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.StarlarkFunctionInfo;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/** Contains a number of utility methods for markdown rendering. */
+public final class MarkdownUtil {
+ private static final int MAX_LINE_LENGTH = 100;
+
+ /**
+ * Return a string that formats the input string so it is displayable in a markdown table cell.
+ * This performs the following operations:
+ *
+ * <ul>
+ * <li>Trims the string of leading/trailing whitespace.
+ * <li>Transforms the string using {@link #htmlEscape}.
+ * <li>Transforms multline code (```) tags into preformatted code HTML tags.
+ * <li>Transforms single-tick code (`) tags into code HTML tags.
+ * <li>Transforms 'new paraphgraph' patterns (two or more sequential newline characters) into
+ * line break HTML tags.
+ * <li>Turns lingering new line tags into spaces (as they generally indicate intended line wrap.
+ * </ul>
+ */
+ public String markdownCellFormat(String docString) {
+ String resultString = htmlEscape(docString.trim());
+
+ resultString = replaceWithTag(resultString, "```", "<pre><code>", "</code></pre>");
+ resultString = replaceWithTag(resultString, "`", "<code>", "</code>");
+
+ return resultString.replaceAll("\n(\\s*\n)+", "<br><br>").replace('\n', ' ');
+ }
+
+ private static String replaceWithTag(
+ String wholeString, String stringToReplace, String openTag, String closeTag) {
+ String remainingString = wholeString;
+ StringBuilder resultString = new StringBuilder();
+
+ boolean openTagNext = true;
+ int index = remainingString.indexOf(stringToReplace);
+ while (index > -1) {
+ resultString.append(remainingString, 0, index);
+ resultString.append(openTagNext ? openTag : closeTag);
+ openTagNext = !openTagNext;
+ remainingString = remainingString.substring(index + stringToReplace.length());
+ index = remainingString.indexOf(stringToReplace);
+ }
+ resultString.append(remainingString);
+ return resultString.toString();
+ }
+
+ /**
+ * Return a string that escapes angle brackets for HTML.
+ *
+ * <p>For example: 'Information with <brackets>.' becomes 'Information with <brackets>'.
+ */
+ public String htmlEscape(String docString) {
+ return docString.replace("<", "<").replace(">", ">");
+ }
+
+ private static final Pattern CONSECUTIVE_BACKTICKS = Pattern.compile("`+");
+
+ /**
+ * Returns a Markdown code span (e.g. {@code `return foo;`}) that contains the given literal text,
+ * which may itself contain backticks.
+ *
+ * <p>For example:
+ *
+ * <ul>
+ * <li>{@code markdownCodeSpan("foo")} returns {@code "`foo`"}
+ * <li>{@code markdownCodeSpan("fo`o")} returns {@code "``fo`o``"}
+ * <li>{@code markdownCodeSpan("`foo`")} returns {@code "`` foo` ``""}
+ * </ul>
+ */
+ public static String markdownCodeSpan(String code) {
+ // https://github.github.com/gfm/#code-span
+ int numConsecutiveBackticks =
+ CONSECUTIVE_BACKTICKS
+ .matcher(code)
+ .results()
+ .map(match -> match.end() - match.start())
+ .max(naturalOrder())
+ .orElse(0);
+ String padding = code.startsWith("`") || code.endsWith("`") ? " " : "";
+ return String.format(
+ "%1$s%2$s%3$s%2$s%1$s", "`".repeat(numConsecutiveBackticks + 1), padding, code);
+ }
+
+ /**
+ * Return a string representing the rule summary for the given rule with the given name.
+ *
+ * For example: 'my_rule(foo, bar)'.
+ * The summary will contain hyperlinks for each attribute.
+ */
+ @SuppressWarnings("unused") // Used by markdown template.
+ public String ruleSummary(String ruleName, RuleInfo ruleInfo) {
+ List<String> attributeNames =
+ ruleInfo.getAttributeList().stream()
+ .map(AttributeInfo::getName)
+ .collect(Collectors.toList());
+ return summary(ruleName, attributeNames);
+ }
+
+ /**
+ * Return a string representing the summary for the given provider with the given name.
+ *
+ * For example: 'MyInfo(foo, bar)'.
+ * The summary will contain hyperlinks for each field.
+ */
+ @SuppressWarnings("unused") // Used by markdown template.
+ public String providerSummary(String providerName, ProviderInfo providerInfo) {
+ List<String> fieldNames =
+ providerInfo.getFieldInfoList().stream()
+ .map(field -> field.getName())
+ .collect(Collectors.toList());
+ return summary(providerName, fieldNames);
+ }
+
+ /**
+ * Return a string representing the aspect summary for the given aspect with the given name.
+ *
+ * <p>For example: 'my_aspect(foo, bar)'. The summary will contain hyperlinks for each attribute.
+ */
+ @SuppressWarnings("unused") // Used by markdown template.
+ public String aspectSummary(String aspectName, AspectInfo aspectInfo) {
+ List<String> attributeNames =
+ aspectInfo.getAttributeList().stream()
+ .map(AttributeInfo::getName)
+ .collect(Collectors.toList());
+ return summary(aspectName, attributeNames);
+ }
+
+ /**
+ * Return a string representing the summary for the given user-defined function.
+ *
+ * <p>For example: 'my_func(foo, bar)'. The summary will contain hyperlinks for each parameter.
+ */
+ @SuppressWarnings("unused") // Used by markdown template.
+ public String funcSummary(StarlarkFunctionInfo funcInfo) {
+ List<String> paramNames =
+ funcInfo.getParameterList().stream()
+ .map(FunctionParamInfo::getName)
+ .collect(Collectors.toList());
+ return summary(funcInfo.getFunctionName(), paramNames);
+ }
+
+ private static String summary(String functionName, List<String> paramNames) {
+ List<List<String>> paramLines = wrap(functionName, paramNames, MAX_LINE_LENGTH);
+ List<String> paramLinksLines = new ArrayList<>();
+ for (List<String> params : paramLines) {
+ String paramLinksLine =
+ params.stream()
+ .map(param -> String.format("<a href=\"#%s-%s\">%s</a>", functionName, param, param))
+ .collect(Collectors.joining(", "));
+ paramLinksLines.add(paramLinksLine);
+ }
+ String paramList =
+ Joiner.on(",\n" + " ".repeat(functionName.length() + 1)).join(paramLinksLines);
+ return String.format("%s(%s)", functionName, paramList);
+ }
+
+ /**
+ * Wraps the given function parameter names to be able to construct a function summary that stays
+ * within the provided line length limit.
+ *
+ * @param functionName the function name.
+ * @param paramNames the function parameter names.
+ * @param maxLineLength the maximal line length.
+ * @return the lines with the wrapped parameter names.
+ */
+ private static List<List<String>> wrap(
+ String functionName, List<String> paramNames, int maxLineLength) {
+ List<List<String>> paramLines = new ArrayList<>();
+ ImmutableList.Builder<String> linesBuilder = new ImmutableList.Builder<>();
+ int leading = functionName.length();
+ int length = leading;
+ int punctuation = 2; // cater for left parenthesis/space before and comma after parameter
+ for (String paramName : paramNames) {
+ length += paramName.length() + punctuation;
+ if (length > maxLineLength) {
+ paramLines.add(linesBuilder.build());
+ length = leading + paramName.length();
+ linesBuilder = new ImmutableList.Builder<>();
+ }
+ linesBuilder.add(paramName);
+ }
+ paramLines.add(linesBuilder.build());
+ return paramLines;
+ }
+
+ /**
+ * Returns a string describing the given attribute's type. The description consists of a hyperlink
+ * if there is a relevant hyperlink to Bazel documentation available.
+ */
+ public String attributeTypeString(AttributeInfo attrInfo) {
+ String typeLink;
+ switch (attrInfo.getType()) {
+ case LABEL:
+ case LABEL_LIST:
+ case OUTPUT:
+ typeLink = "https://bazel.build/concepts/labels";
+ break;
+ case NAME:
+ typeLink = "https://bazel.build/concepts/labels#target-names";
+ break;
+ case STRING_DICT:
+ case STRING_LIST_DICT:
+ case LABEL_STRING_DICT:
+ typeLink = "https://bazel.build/rules/lib/dict";
+ break;
+ default:
+ typeLink = null;
+ break;
+ }
+ if (typeLink == null) {
+ return attributeTypeDescription(attrInfo.getType());
+ } else {
+ return String.format(
+ "<a href=\"%s\">%s</a>", typeLink, attributeTypeDescription(attrInfo.getType()));
+ }
+ }
+
+ public String mandatoryString(AttributeInfo attrInfo) {
+ return attrInfo.getMandatory() ? "required" : "optional";
+ }
+
+ /**
+ * Returns "required" if providing a value for this parameter is mandatory. Otherwise, returns
+ * "optional".
+ */
+ public String mandatoryString(FunctionParamInfo paramInfo) {
+ return paramInfo.getMandatory() ? "required" : "optional";
+ }
+
+ /**
+ * Return a string explaining what providers an attribute requires. Adds hyperlinks to providers.
+ */
+ public String attributeProviders(AttributeInfo attributeInfo) {
+ List<ProviderNameGroup> providerNames = attributeInfo.getProviderNameGroupList();
+ List<String> finalProviderNames = new ArrayList<>();
+ for (ProviderNameGroup providerNameList : providerNames) {
+ List<String> providers = providerNameList.getProviderNameList();
+ finalProviderNames.add(Joiner.on(", ").join(providers));
+ }
+ return Joiner.on("; or ").join(finalProviderNames);
+ }
+
+ private static String attributeTypeDescription(AttributeType attributeType) {
+ switch (attributeType) {
+ case NAME:
+ return "Name";
+ case INT:
+ return "Integer";
+ case STRING:
+ return "String";
+ case STRING_LIST:
+ return "List of strings";
+ case INT_LIST:
+ return "List of integers";
+ case BOOLEAN:
+ return "Boolean";
+ case LABEL_STRING_DICT:
+ return "Dictionary: Label -> String";
+ case STRING_DICT:
+ return "Dictionary: String -> String";
+ case STRING_LIST_DICT:
+ return "Dictionary: String -> List of strings";
+ case LABEL:
+ case OUTPUT:
+ return "Label";
+ case LABEL_LIST:
+ case OUTPUT_LIST:
+ return "List of labels";
+ case UNKNOWN:
+ case UNRECOGNIZED:
+ throw new IllegalArgumentException("Unhandled type " + attributeType);
+ }
+ throw new IllegalArgumentException("Unhandled type " + attributeType);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/skydoc/rendering/BUILD b/src/test/java/com/google/devtools/build/skydoc/rendering/BUILD
new file mode 100644
index 0000000..3405102
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skydoc/rendering/BUILD
@@ -0,0 +1,27 @@
+load("@rules_java//java:defs.bzl", "java_test")
+
+package(
+ default_applicable_licenses = ["//:license"],
+ default_visibility = [
+ "//src:__subpackages__",
+ "//stardoc:__subpackages__",
+ ],
+)
+
+filegroup(
+ name = "srcs",
+ testonly = 0,
+ srcs = glob(["*"]),
+ visibility = ["//:__pkg__"],
+)
+
+java_test(
+ name = "MarkdownUtilTest",
+ size = "small",
+ srcs = ["MarkdownUtilTest.java"],
+ deps = [
+ "//src/main/java/com/google/devtools/build/skydoc/rendering",
+ "@maven//:com_google_truth_truth",
+ "@maven//:junit_junit",
+ ],
+)
diff --git a/src/test/java/com/google/devtools/build/skydoc/rendering/MarkdownUtilTest.java b/src/test/java/com/google/devtools/build/skydoc/rendering/MarkdownUtilTest.java
new file mode 100644
index 0000000..cf84964
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skydoc/rendering/MarkdownUtilTest.java
@@ -0,0 +1,50 @@
+// Copyright 2023 The Bazel Authors. All rights reserved.
+//
+// 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 com.google.devtools.build.skydoc.rendering;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for MarkdownUtil. */
+@RunWith(JUnit4.class)
+public class MarkdownUtilTest {
+
+ MarkdownUtil util = new MarkdownUtil();
+
+ @Test
+ public void markdownCodeSpan() {
+ assertThat(MarkdownUtil.markdownCodeSpan("")).isEqualTo("``");
+ assertThat(MarkdownUtil.markdownCodeSpan("foo bar ")).isEqualTo("`foo bar `");
+ }
+
+ @Test
+ public void markdownCodeSpan_backticks() {
+ assertThat(MarkdownUtil.markdownCodeSpan("foo`bar")).isEqualTo("``foo`bar``");
+ assertThat(MarkdownUtil.markdownCodeSpan("foo``bar")).isEqualTo("```foo``bar```");
+ assertThat(MarkdownUtil.markdownCodeSpan("foo`bar```baz``quz"))
+ .isEqualTo("````foo`bar```baz``quz````");
+ }
+
+ @Test
+ public void markdownCodeSpan_backticksPadding() {
+ assertThat(MarkdownUtil.markdownCodeSpan("`foo")).isEqualTo("`` `foo ``");
+ assertThat(MarkdownUtil.markdownCodeSpan("``foo")).isEqualTo("``` ``foo ```");
+ assertThat(MarkdownUtil.markdownCodeSpan("foo`")).isEqualTo("`` foo` ``");
+ assertThat(MarkdownUtil.markdownCodeSpan("foo``")).isEqualTo("``` foo`` ```");
+ }
+}
diff --git a/stardoc/BUILD b/stardoc/BUILD
index 045774f..da02ce0 100644
--- a/stardoc/BUILD
+++ b/stardoc/BUILD
@@ -63,18 +63,9 @@
visibility = ["//visibility:public"],
)
-java_binary(
+alias(
name = "renderer",
- main_class = "com.google.devtools.build.skydoc.renderer.RendererMain",
- runtime_deps = [
- ":prebuilt_renderer_binary",
- ],
-)
-
-java_import(
- name = "prebuilt_renderer_binary",
- jars = ["renderer_binary.jar"],
- visibility = ["//visibility:private"],
+ actual = "//src/main/java/com/google/devtools/build/skydoc/renderer",
)
# Sources needed for release tarball.
diff --git a/stardoc/proto/BUILD b/stardoc/proto/BUILD
index 6e3782c..4e9619b 100644
--- a/stardoc/proto/BUILD
+++ b/stardoc/proto/BUILD
@@ -1,3 +1,5 @@
+load("@rules_java//java:defs.bzl", "java_proto_library")
+
licenses(["notice"])
package(
@@ -15,3 +17,13 @@
] + glob(["*.proto"]),
visibility = ["//:__pkg__"],
)
+
+proto_library(
+ name = "stardoc_output_proto",
+ srcs = ["stardoc_output.proto"],
+)
+
+java_proto_library(
+ name = "stardoc_output_java_proto",
+ deps = [":stardoc_output_proto"],
+)
diff --git a/stardoc/proto/stardoc_output.proto b/stardoc/proto/stardoc_output.proto
index e35e714..7176213 100644
--- a/stardoc/proto/stardoc_output.proto
+++ b/stardoc/proto/stardoc_output.proto
@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
+// Vendored from src/main/java/com/google/devtools/build/skydoc/rendering/proto/stardoc_output.proto
+// in the Bazel source tree at commit e33c2d14728aea6914b165fe11f08ff4982196ca
+//
// Protos for Stardoc data.
//
// Stardoc collects information about Starlark functions, providers, and rules.
@@ -23,9 +26,9 @@
option java_package = "com.google.devtools.build.skydoc.rendering.proto";
option java_outer_classname = "StardocOutputProtos";
-// The root output proto of Stardoc. A single invocation of Stardoc will output
-// exactly one instance of this proto, representing all documentation for
-// the input Starlark file.
+// The root output proto of Stardoc. An invocation of Stardoc on a single file
+// will output exactly one instance of this proto, representing all
+// documentation for the input Starlark file.
message ModuleInfo {
repeated RuleInfo rule_info = 1;
@@ -37,6 +40,15 @@
// The docstring present at the top of the input Starlark file.
string module_docstring = 5;
+
+ // The display form of the label of the module file (as seen from the
+ // starlark_doc_extract or Stardoc target's repo). Unset when there is no
+ // module file (e.g. when the module is a REPL, or in Bazel's internal tests).
+ string file = 6;
+
+ repeated ModuleExtensionInfo module_extension_info = 7;
+
+ repeated RepositoryRuleInfo repository_rule_info = 8;
}
// Representation of a Starlark rule attribute type. These generally
@@ -63,7 +75,8 @@
// Representation of a Starlark rule definition.
message RuleInfo {
- // The name of the rule.
+ // The name under which the rule is made accessible to a user of this module,
+ // including any structs it is nested in, for example "foo.foo_library".
string rule_name = 1;
// The documentation string of the rule.
@@ -71,11 +84,22 @@
// The attributes of the rule.
repeated AttributeInfo attribute = 3;
+
+ // The module where and the name under which the rule was originally declared.
+ //
+ // Note: legacy Stardoc (0.5.x and earlier) does not set this field.
+ OriginKey origin_key = 4;
+
+ // The list of providers that the rule's implementation must return. Unset if
+ // the rule lists no advertised providers.
+ //
+ // Note: legacy Stardoc (0.5.x and earlier) does not set this field.
+ ProviderNameGroup advertised_providers = 5;
}
-// Representation of a Starlark rule attribute definition, comprised of an
-// attribute name, and a schema defined by a call to one of the 'attr' module
-// methods enumerated at
+// Representation of a Starlark rule, repository rule, or module extension tag
+// attribute definition, comprised of an attribute name, and a schema defined by
+// a call to one of the 'attr' module methods enumerated at
// https://bazel.build/rules/lib/attr
message AttributeInfo {
// The name of the attribute.
@@ -95,26 +119,46 @@
// The target(s) in this attribute must define all the providers of at least
// one of the ProviderNameGroups in this list. If the Attribute Type is not a
// label, a label list, or a label-keyed string dictionary, the field will be
- // left empty.
+ // left empty. For attributes of a repository rule or a module extension tag,
+ // this attribute is meaningless and may be ignored.
+ // TODO(b/290788853): ensure this field is always empty for attributes of a
+ // repository rule or a module extension tag.
repeated ProviderNameGroup provider_name_group = 5;
// The string representation of the default value of this attribute.
string default_value = 6;
}
-// Representation of a set of providers that a rule attribute may be required to
-// have.
+// Representation of a set of providers.
message ProviderNameGroup {
- // The names of the providers that must be given by any dependency appearing
- // in this attribute. The name will be "Unknown Provider" if the name is
- // unidentifiable, for example, if the provider is part of a namespace.
- // TODO(kendalllane): Fix documentation of providers from namespaces.
+ // The names of the providers.
+ //
+ // This field is only intended for rendering human-readable output.
+ // Please use origin_key (a list of the same length and in the same order as
+ // this field) for cross-references and tooling.
+ //
+ // Note: legacy Stardoc (0.5.x and earlier) is unable to extract the name in
+ // some circumstances (for example, if the provider is nested in a struct),
+ // and in that case, the provider name will be "Unknown Provider".
repeated string provider_name = 1;
+
+ // A list of unambiguous references to providers, of the same length and in
+ // the same order as the provider_name list.
+ //
+ // For provider symbols, this means modules where and the names under which
+ // the providers were originally declared.
+ //
+ // For legacy struct providers, origin_key.file is unset.
+ //
+ // Note: legacy Stardoc (0.5.x and earlier) does not set this field.
+ repeated OriginKey origin_key = 2;
}
// Representation of Starlark function definition.
message StarlarkFunctionInfo {
- // The name of the function.
+ // The name under which the function is made accessible to a user of this
+ // module, including any structs it is nested in, for example
+ // "foo.frobnicate".
string function_name = 1;
// The parameters for the function.
@@ -129,6 +173,12 @@
// The deprecation for the function.
FunctionDeprecationInfo deprecated = 5;
+
+ // The module where and the name under which the function was originally
+ // declared.
+ //
+ // Note: legacy Stardoc (0.5.x and earlier) does not set this field.
+ OriginKey origin_key = 6;
}
// Representation of a Starlark function parameter definition.
@@ -174,7 +224,8 @@
// Representation of a Starlark provider definition.
message ProviderInfo {
- // The name of the provider.
+ // The name under which the provider is made accessible to a user of this
+ // module, including any structs it is nested in, for example "foo.FooInfo".
string provider_name = 1;
// The description of the provider.
@@ -182,11 +233,19 @@
// The fields of the provider.
repeated ProviderFieldInfo field_info = 3;
+
+ // The module where and the name under which the provider was originally
+ // declared.
+ //
+ // Note: legacy Stardoc (0.5.x and earlier) does not set this field.
+ OriginKey origin_key = 4;
}
// Representation of a Starlark aspect definition.
message AspectInfo {
- // The name of the aspect.
+ // The name under which the aspect is made accessible to a user of this
+ // module, including any structs it is nested in, for example
+ // "foo.foo_aspect".
string aspect_name = 1;
// The documentation string of the aspect.
@@ -197,4 +256,85 @@
// The attributes of the aspect.
repeated AttributeInfo attribute = 4;
+
+ // The module where and the name under which the aspect was originally
+ // declared.
+ //
+ // Note: legacy Stardoc (0.5.x and earlier) does not set this field.
+ OriginKey origin_key = 5;
+}
+
+// Representation of a Bazel module extension, i.e. the object returned by
+// calling `module_extension(...)`.
+//
+// Note: legacy Stardoc (0.5.x and earlier) does not emit this message.
+message ModuleExtensionInfo {
+ // The name under which the extension is made accessible to a user of this
+ // Starlark module.
+ string extension_name = 1;
+
+ // The documentation string of the extension.
+ string doc_string = 2;
+
+ // The tag classes of the extension.
+ repeated ModuleExtensionTagClassInfo tag_class = 3;
+
+ // The Starlark module where the Bazel module extension was originally
+ // declared; origin_key.name is currently never set.
+ // TODO(arostovtsev): attempt to retrieve the name under which the module
+ // extension was originally declared if it was declared as a global.
+ OriginKey origin_key = 4;
+}
+
+// Representation of a Bazel module extension tag class.
+message ModuleExtensionTagClassInfo {
+ // The name of the tag for this tag class.
+ string tag_name = 1;
+
+ // The documentation string of the tag class.
+ string doc_string = 2;
+
+ // The tag class's attributes.
+ repeated AttributeInfo attribute = 3;
+}
+
+// Representation of a Bazel repository rule, i.e. the object returned by
+// calling `repository_rule(...)`.
+//
+// Note: legacy Stardoc (0.5.x and earlier) does not emit this message, instead
+// using RuleInfo.
+message RepositoryRuleInfo {
+ // The name under which the repository rule is made accessible to a user of
+ // this Starlark module.
+ string rule_name = 1;
+
+ // The documentation string of the repository rule.
+ string doc_string = 2;
+
+ // The attributes of the repository rule.
+ repeated AttributeInfo attribute = 3;
+
+ // Environment variables that this repository rule depends on.
+ repeated string environ = 4;
+
+ // The Starlark module where and the name under which the repository rule was
+ // originally declared.
+ OriginKey origin_key = 5;
+}
+
+// Representation of the origin of a rule, provider, aspect, or function.
+// Intended to be used for building unambiguous cross-references: for example,
+// between an element of a ProviderNameGroup required by a rule attribute and
+// its corresponding ProviderInfo.
+message OriginKey {
+ // The name under which the entity was originally exported. Unset when the
+ // entity was not exported in its module.
+ string name = 1;
+
+ // The display form of the label of the module file in which the entity was
+ // originally declared (as seen from the starlark_doc_extract or Stardoc
+ // target's repo), or "<native>" for Bazel's built-in entities implemented in
+ // Java. Unset when there is no module file (such as for legacy struct
+ // providers, when the module is a REPL, or in Bazel's internal tests).
+ string file = 2;
}
diff --git a/stardoc/renderer_binary.jar b/stardoc/renderer_binary.jar
deleted file mode 100755
index a2f8897..0000000
--- a/stardoc/renderer_binary.jar
+++ /dev/null
Binary files differ
diff --git a/test/BUILD b/test/BUILD
index 1dd7b70..6dfe44e 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -144,7 +144,7 @@
input_file = "testdata/filter_rules_test/input.bzl",
symbol_names = [
"my_rule",
- "whitelisted_dep_rule",
+ "allowlisted_dep_rule",
],
deps = [
"testdata/filter_rules_test/dep.bzl",
@@ -164,13 +164,19 @@
)
stardoc_test(
+ name = "function_wrap_multiple_lines_test",
+ golden_file = "testdata/function_wrap_multiple_lines_test/golden.md",
+ input_file = "testdata/function_wrap_multiple_lines_test/input.bzl",
+)
+
+stardoc_test(
name = "namespace_test",
golden_file = "testdata/namespace_test/golden.md",
input_file = "testdata/namespace_test/input.bzl",
)
stardoc_test(
- name = "namespace_test_with_whitelist",
+ name = "namespace_test_with_allowlist",
golden_file = "testdata/namespace_test/golden.md",
input_file = "testdata/namespace_test/input.bzl",
symbol_names = [
@@ -185,9 +191,9 @@
)
stardoc_test(
- name = "multi_level_namespace_test_with_whitelist",
- golden_file = "testdata/multi_level_namespace_test_with_whitelist/golden.md",
- input_file = "testdata/multi_level_namespace_test_with_whitelist/input.bzl",
+ name = "multi_level_namespace_test_with_allowlist",
+ golden_file = "testdata/multi_level_namespace_test_with_allowlist/golden.md",
+ input_file = "testdata/multi_level_namespace_test_with_allowlist/input.bzl",
symbol_names = [
"my_namespace",
"other_namespace.foo.nothing",
@@ -201,6 +207,12 @@
)
stardoc_test(
+ name = "pure_markdown_template_test",
+ golden_file = "testdata/pure_markdown_template_test/golden.md",
+ input_file = "testdata/pure_markdown_template_test/input.bzl",
+)
+
+stardoc_test(
name = "py_rule_test",
golden_file = "testdata/py_rule_test/golden.md",
input_file = "testdata/py_rule_test/input.bzl",
diff --git a/test/stardoc_test.bzl b/test/stardoc_test.bzl
index cb356af..fc44ba8 100644
--- a/test/stardoc_test.bzl
+++ b/test/stardoc_test.bzl
@@ -60,7 +60,6 @@
input_file = input_file,
golden_file = golden_file,
stardoc_bin = "@io_bazel//src/main/java/com/google/devtools/build/skydoc:skydoc_deploy.jar",
- renderer_bin = "@io_bazel//src/main/java/com/google/devtools/build/skydoc/renderer",
test = test,
**kwargs
)
@@ -71,7 +70,6 @@
input_file = input_file,
golden_file = golden_file,
stardoc_bin = "@io_bazel//src/main/java/com/google/devtools/build/skydoc:skydoc_deploy.jar",
- renderer_bin = "@io_bazel//src/main/java/com/google/devtools/build/skydoc/renderer",
test = test,
**kwargs
)
@@ -83,7 +81,6 @@
input_file,
golden_file,
stardoc_bin,
- renderer_bin,
test,
**kwargs):
actual_generated_doc = "%s.out" % genrule_name
@@ -107,7 +104,6 @@
out = actual_generated_doc,
input = input_file,
deps = [lib_name],
- renderer = renderer_bin,
stardoc = stardoc_bin,
**kwargs
)
@@ -117,7 +113,6 @@
out = actual_generated_doc,
input = input_file,
deps = [lib_name],
- renderer = renderer_bin,
stardoc = stardoc_bin,
**kwargs
)
diff --git a/test/testdata/filter_rules_test/golden.md b/test/testdata/filter_rules_test/golden.md
index 7e85581..2801a16 100755
--- a/test/testdata/filter_rules_test/golden.md
+++ b/test/testdata/filter_rules_test/golden.md
@@ -2,6 +2,26 @@
+<a id="allowlisted_dep_rule"></a>
+
+## allowlisted_dep_rule
+
+<pre>
+allowlisted_dep_rule(<a href="#allowlisted_dep_rule-name">name</a>, <a href="#allowlisted_dep_rule-first">first</a>, <a href="#allowlisted_dep_rule-second">second</a>)
+</pre>
+
+This is the dep rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="allowlisted_dep_rule-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
+| <a id="allowlisted_dep_rule-first"></a>first | dep's my_rule doc string | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
+| <a id="allowlisted_dep_rule-second"></a>second | - | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
+
+
<a id="my_rule"></a>
## my_rule
@@ -22,23 +42,3 @@
| <a id="my_rule-second"></a>second | - | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
-<a id="whitelisted_dep_rule"></a>
-
-## whitelisted_dep_rule
-
-<pre>
-whitelisted_dep_rule(<a href="#whitelisted_dep_rule-name">name</a>, <a href="#whitelisted_dep_rule-first">first</a>, <a href="#whitelisted_dep_rule-second">second</a>)
-</pre>
-
-This is the dep rule. It does stuff.
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| <a id="whitelisted_dep_rule-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
-| <a id="whitelisted_dep_rule-first"></a>first | dep's my_rule doc string | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
-| <a id="whitelisted_dep_rule-second"></a>second | - | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
-
-
diff --git a/test/testdata/filter_rules_test/input.bzl b/test/testdata/filter_rules_test/input.bzl
index 5d05b9b..08cc012 100644
--- a/test/testdata/filter_rules_test/input.bzl
+++ b/test/testdata/filter_rules_test/input.bzl
@@ -1,13 +1,10 @@
# buildifier: disable=module-docstring
load(
":testdata/filter_rules_test/dep.bzl",
+ "my_rule_impl",
dep_rule = "my_rule",
)
-def my_rule_impl(ctx):
- _ignore = [ctx] # @unused
- return []
-
my_rule = rule(
implementation = my_rule_impl,
doc = "This is my rule. It does stuff.",
@@ -29,7 +26,7 @@
},
)
-whitelisted_dep_rule = dep_rule
+allowlisted_dep_rule = dep_rule
yet_another_rule = rule(
implementation = my_rule_impl,
diff --git a/test/testdata/function_basic_test/golden.md b/test/testdata/function_basic_test/golden.md
index 138f3c2..3f72514 100755
--- a/test/testdata/function_basic_test/golden.md
+++ b/test/testdata/function_basic_test/golden.md
@@ -48,6 +48,24 @@
Use literally anything but this function.
+<a id="param_doc_multiline"></a>
+
+## param_doc_multiline
+
+<pre>
+param_doc_multiline(<a href="#param_doc_multiline-complex">complex</a>)
+</pre>
+
+Has a complex parameter.
+
+**PARAMETERS**
+
+
+| Name | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="param_doc_multiline-complex"></a>complex | A parameter with some non-obvious behavior.<br><br> For example, it does things that require **multiple paragraphs** to explain.<br><br>Note: we should preserve the nested indent in the following code:<br><br><pre><code>json { "key": "value" } </code></pre> | none |
+
+
<a id="returns_a_thing"></a>
## returns_a_thing
diff --git a/test/testdata/function_basic_test/input.bzl b/test/testdata/function_basic_test/input.bzl
index 93bf711..2d75025 100644
--- a/test/testdata/function_basic_test/input.bzl
+++ b/test/testdata/function_basic_test/input.bzl
@@ -54,6 +54,25 @@
"""
pass
+# buildifier: disable=unused-variable
def undocumented_function(a, b, c):
- _ignore = [a, b, c] # @unused
+ pass
+
+# buildifier: disable=unused-variable
+def param_doc_multiline(complex):
+ """Has a complex parameter.
+
+ Args:
+ complex: A parameter with some non-obvious behavior.
+
+ For example, it does things that require **multiple paragraphs** to explain.
+
+ Note: we should preserve the nested indent in the following code:
+
+ ```json
+ {
+ "key": "value"
+ }
+ ```
+ """
pass
diff --git a/test/testdata/function_wrap_multiple_lines_test/golden.md b/test/testdata/function_wrap_multiple_lines_test/golden.md
new file mode 100644
index 0000000..2f1a8a4
--- /dev/null
+++ b/test/testdata/function_wrap_multiple_lines_test/golden.md
@@ -0,0 +1,56 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+Rules for ANTLR 3.
+
+<a id="antlr"></a>
+
+## antlr
+
+<pre>
+antlr(<a href="#antlr-name">name</a>, <a href="#antlr-deps">deps</a>, <a href="#antlr-srcs">srcs</a>, <a href="#antlr-Xconversiontimeout">Xconversiontimeout</a>, <a href="#antlr-Xdbgconversion">Xdbgconversion</a>, <a href="#antlr-Xdbgst">Xdbgst</a>, <a href="#antlr-Xdfa">Xdfa</a>, <a href="#antlr-Xdfaverbose">Xdfaverbose</a>, <a href="#antlr-Xgrtree">Xgrtree</a>, <a href="#antlr-Xm">Xm</a>,
+ <a href="#antlr-Xmaxdfaedges">Xmaxdfaedges</a>, <a href="#antlr-Xmaxinlinedfastates">Xmaxinlinedfastates</a>, <a href="#antlr-Xminswitchalts">Xminswitchalts</a>, <a href="#antlr-Xmultithreaded">Xmultithreaded</a>, <a href="#antlr-Xnfastates">Xnfastates</a>, <a href="#antlr-Xnocollapse">Xnocollapse</a>,
+ <a href="#antlr-Xnomergestopstates">Xnomergestopstates</a>, <a href="#antlr-Xnoprune">Xnoprune</a>, <a href="#antlr-XsaveLexer">XsaveLexer</a>, <a href="#antlr-Xwatchconversion">Xwatchconversion</a>, <a href="#antlr-debug">debug</a>, <a href="#antlr-depend">depend</a>, <a href="#antlr-dfa">dfa</a>, <a href="#antlr-dump">dump</a>, <a href="#antlr-imports">imports</a>,
+ <a href="#antlr-language">language</a>, <a href="#antlr-message_format">message_format</a>, <a href="#antlr-nfa">nfa</a>, <a href="#antlr-package">package</a>, <a href="#antlr-profile">profile</a>, <a href="#antlr-report">report</a>, <a href="#antlr-trace">trace</a>)
+</pre>
+
+Runs [ANTLR 3](https://www.antlr3.org//) on a set of grammars.
+
+**ATTRIBUTES**
+
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="antlr-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
+| <a id="antlr-deps"></a>deps | The dependencies to use. Defaults to the most recent ANTLR 3 release, but if you need to use a different version, you can specify the dependencies here. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | <code>[Label("@antlr3_runtimes//:tool")]</code> |
+| <a id="antlr-srcs"></a>srcs | The grammar files to process. | <a href="https://bazel.build/concepts/labels">List of labels</a> | required | |
+| <a id="antlr-Xconversiontimeout"></a>Xconversiontimeout | Set NFA conversion timeout for each decision. | Integer | optional | <code>0</code> |
+| <a id="antlr-Xdbgconversion"></a>Xdbgconversion | Dump lots of info during NFA conversion. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xdbgst"></a>Xdbgst | Put tags at start/stop of all templates in output. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xdfa"></a>Xdfa | Print DFA as text. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xdfaverbose"></a>Xdfaverbose | Generate DFA states in DOT with NFA configs. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xgrtree"></a>Xgrtree | Print the grammar AST. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xm"></a>Xm | Max number of rule invocations during conversion. | Integer | optional | <code>0</code> |
+| <a id="antlr-Xmaxdfaedges"></a>Xmaxdfaedges | Max "comfortable" number of edges for single DFA state. | Integer | optional | <code>0</code> |
+| <a id="antlr-Xmaxinlinedfastates"></a>Xmaxinlinedfastates | Max DFA states before table used rather than inlining. | Integer | optional | <code>0</code> |
+| <a id="antlr-Xminswitchalts"></a>Xminswitchalts | Don't generate switch() statements for dfas smaller than given number. | Integer | optional | <code>0</code> |
+| <a id="antlr-Xmultithreaded"></a>Xmultithreaded | Run the analysis in 2 threads. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xnfastates"></a>Xnfastates | For nondeterminisms, list NFA states for each path. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xnocollapse"></a>Xnocollapse | Collapse incident edges into DFA states. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xnomergestopstates"></a>Xnomergestopstates | Max DFA states before table used rather than inlining. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xnoprune"></a>Xnoprune | Do not test EBNF block exit branches. | Boolean | optional | <code>False</code> |
+| <a id="antlr-XsaveLexer"></a>XsaveLexer | For nondeterminisms, list NFA states for each path. | Boolean | optional | <code>False</code> |
+| <a id="antlr-Xwatchconversion"></a>Xwatchconversion | Don't delete temporary lexers generated from combined grammars. | Boolean | optional | <code>False</code> |
+| <a id="antlr-debug"></a>debug | Generate a parser that emits debugging events. | Boolean | optional | <code>False</code> |
+| <a id="antlr-depend"></a>depend | Generate file dependencies; don't actually run antlr. | Boolean | optional | <code>False</code> |
+| <a id="antlr-dfa"></a>dfa | Generate a DFA for each decision point. | Boolean | optional | <code>False</code> |
+| <a id="antlr-dump"></a>dump | Print out the grammar without actions. | Boolean | optional | <code>False</code> |
+| <a id="antlr-imports"></a>imports | The grammar and .tokens files to import. Must be all in the same directory. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | <code>[]</code> |
+| <a id="antlr-language"></a>language | The code generation target language. Either C, Cpp, CSharp2, CSharp3, JavaScript, Java, ObjC, Python, Python3 or Ruby (case-sensitive). | String | optional | <code>""</code> |
+| <a id="antlr-message_format"></a>message_format | Specify output style for messages. | String | optional | <code>""</code> |
+| <a id="antlr-nfa"></a>nfa | Generate an NFA for each rule. | Boolean | optional | <code>False</code> |
+| <a id="antlr-package"></a>package | The package/namespace for the generated code. | String | optional | <code>""</code> |
+| <a id="antlr-profile"></a>profile | Generate a parser that computes profiling information. | Boolean | optional | <code>False</code> |
+| <a id="antlr-report"></a>report | Print out a report about the grammar(s) processed. | Boolean | optional | <code>False</code> |
+| <a id="antlr-trace"></a>trace | Generate a parser with trace output. If the default output is not enough, you can override the traceIn and traceOut methods. | Boolean | optional | <code>False</code> |
+
+
diff --git a/test/testdata/function_wrap_multiple_lines_test/input.bzl b/test/testdata/function_wrap_multiple_lines_test/input.bzl
new file mode 100644
index 0000000..c822551
--- /dev/null
+++ b/test/testdata/function_wrap_multiple_lines_test/input.bzl
@@ -0,0 +1,54 @@
+"""Rules for ANTLR 3."""
+
+# buildifier: disable=unused-variable
+def _generate(ctx):
+ return None
+
+antlr = rule(
+ implementation = _generate,
+ doc = "Runs [ANTLR 3](https://www.antlr3.org//) on a set of grammars.",
+ attrs = {
+ "debug": attr.bool(default = False, doc = "Generate a parser that emits debugging events."),
+ "depend": attr.bool(default = False, doc = "Generate file dependencies; don't actually run antlr."),
+ "deps": attr.label_list(
+ default = [Label("@antlr3_runtimes//:tool")],
+ doc = """
+The dependencies to use. Defaults to the most recent ANTLR 3 release,
+but if you need to use a different version, you can specify the
+dependencies here.
+""",
+ ),
+ "dfa": attr.bool(default = False, doc = "Generate a DFA for each decision point."),
+ "dump": attr.bool(default = False, doc = "Print out the grammar without actions."),
+ "imports": attr.label_list(allow_files = True, doc = "The grammar and .tokens files to import. Must be all in the same directory."),
+ "language": attr.string(doc = "The code generation target language. Either C, Cpp, CSharp2, CSharp3, JavaScript, Java, ObjC, Python, Python3 or Ruby (case-sensitive)."),
+ "message_format": attr.string(doc = "Specify output style for messages."),
+ "nfa": attr.bool(default = False, doc = "Generate an NFA for each rule."),
+ "package": attr.string(doc = "The package/namespace for the generated code."),
+ "profile": attr.bool(default = False, doc = "Generate a parser that computes profiling information."),
+ "report": attr.bool(default = False, doc = "Print out a report about the grammar(s) processed."),
+ "srcs": attr.label_list(allow_files = True, mandatory = True, doc = "The grammar files to process."),
+ "trace": attr.bool(default = False, doc = "Generate a parser with trace output. If the default output is not enough, you can override the traceIn and traceOut methods."),
+ "Xconversiontimeout": attr.int(doc = "Set NFA conversion timeout for each decision."),
+ "Xdbgconversion": attr.bool(default = False, doc = "Dump lots of info during NFA conversion."),
+ "Xdbgst": attr.bool(default = False, doc = "Put tags at start/stop of all templates in output."),
+ "Xdfa": attr.bool(default = False, doc = "Print DFA as text."),
+ "Xdfaverbose": attr.bool(default = False, doc = "Generate DFA states in DOT with NFA configs."),
+ "Xgrtree": attr.bool(default = False, doc = "Print the grammar AST."),
+ "Xm": attr.int(doc = "Max number of rule invocations during conversion."),
+ "Xmaxdfaedges": attr.int(doc = "Max "comfortable" number of edges for single DFA state."),
+ "Xmaxinlinedfastates": attr.int(doc = "Max DFA states before table used rather than inlining."),
+ "Xminswitchalts": attr.int(doc = "Don't generate switch() statements for dfas smaller than given number."),
+ "Xmultithreaded": attr.bool(default = False, doc = "Run the analysis in 2 threads."),
+ "Xnfastates": attr.bool(default = False, doc = "For nondeterminisms, list NFA states for each path."),
+ "Xnocollapse": attr.bool(default = False, doc = "Collapse incident edges into DFA states."),
+ "Xnoprune": attr.bool(default = False, doc = "Do not test EBNF block exit branches."),
+ "Xnomergestopstates": attr.bool(default = False, doc = "Max DFA states before table used rather than inlining."),
+ "XsaveLexer": attr.bool(default = False, doc = "For nondeterminisms, list NFA states for each path."),
+ "Xwatchconversion": attr.bool(default = False, doc = "Don't delete temporary lexers generated from combined grammars."),
+ "_tool": attr.label(
+ executable = True,
+ cfg = "exec",
+ ),
+ },
+)
diff --git a/test/testdata/misc_apis_test/golden.md b/test/testdata/misc_apis_test/golden.md
index 7b94d9f..34686ee 100755
--- a/test/testdata/misc_apis_test/golden.md
+++ b/test/testdata/misc_apis_test/golden.md
@@ -7,7 +7,7 @@
## my_rule
<pre>
-my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-deps">deps</a>, <a href="#my_rule-extra_arguments">extra_arguments</a>, <a href="#my_rule-out">out</a>, <a href="#my_rule-src">src</a>, <a href="#my_rule-tool">tool</a>)
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-deps">deps</a>, <a href="#my_rule-src">src</a>, <a href="#my_rule-out">out</a>, <a href="#my_rule-extra_arguments">extra_arguments</a>, <a href="#my_rule-tool">tool</a>)
</pre>
This rule exercises some of the build API.
@@ -19,9 +19,9 @@
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <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-deps"></a>deps | A list of dependencies. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | <code>[]</code> |
-| <a id="my_rule-extra_arguments"></a>extra_arguments | - | List of strings | optional | <code>[]</code> |
-| <a id="my_rule-out"></a>out | The output file. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="my_rule-src"></a>src | The source file. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>None</code> |
+| <a id="my_rule-out"></a>out | The output file. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
+| <a id="my_rule-extra_arguments"></a>extra_arguments | - | List of strings | optional | <code>[]</code> |
| <a id="my_rule-tool"></a>tool | The location of the tool to use. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | <code>//foo/bar/baz:target</code> |
diff --git a/test/testdata/multi_level_namespace_test/golden.md b/test/testdata/multi_level_namespace_test/golden.md
index 85791c9..3e753c0 100755
--- a/test/testdata/multi_level_namespace_test/golden.md
+++ b/test/testdata/multi_level_namespace_test/golden.md
@@ -2,26 +2,16 @@
A test that verifies documenting a multi-leveled namespace of functions.
-<a id="my_namespace.min"></a>
+<a id="my_namespace.foo.bar.baz"></a>
-## my_namespace.min
+## my_namespace.foo.bar.baz
<pre>
-my_namespace.min(<a href="#my_namespace.min-integers">integers</a>)
+my_namespace.foo.bar.baz()
</pre>
-Returns the minimum of given elements.
+This function does nothing.
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="my_namespace.min-integers"></a>integers | A list of integers. Must not be empty. | none |
-
-**RETURNS**
-
-The minimum integer in the given list.
<a id="my_namespace.math.min"></a>
@@ -46,12 +36,34 @@
The minimum integer in the given list.
-<a id="my_namespace.foo.bar.baz"></a>
+<a id="my_namespace.min"></a>
-## my_namespace.foo.bar.baz
+## my_namespace.min
<pre>
-my_namespace.foo.bar.baz()
+my_namespace.min(<a href="#my_namespace.min-integers">integers</a>)
+</pre>
+
+Returns the minimum of given elements.
+
+**PARAMETERS**
+
+
+| Name | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="my_namespace.min-integers"></a>integers | A list of integers. Must not be empty. | none |
+
+**RETURNS**
+
+The minimum integer in the given list.
+
+
+<a id="my_namespace.one.three.does_nothing"></a>
+
+## my_namespace.one.three.does_nothing
+
+<pre>
+my_namespace.one.three.does_nothing()
</pre>
This function does nothing.
@@ -80,15 +92,3 @@
The minimum integer in the given list.
-<a id="my_namespace.one.three.does_nothing"></a>
-
-## my_namespace.one.three.does_nothing
-
-<pre>
-my_namespace.one.three.does_nothing()
-</pre>
-
-This function does nothing.
-
-
-
diff --git a/test/testdata/multi_level_namespace_test_with_whitelist/golden.md b/test/testdata/multi_level_namespace_test_with_allowlist/golden.md
similarity index 91%
rename from test/testdata/multi_level_namespace_test_with_whitelist/golden.md
rename to test/testdata/multi_level_namespace_test_with_allowlist/golden.md
index 1ca1608..f35b10d 100644
--- a/test/testdata/multi_level_namespace_test_with_whitelist/golden.md
+++ b/test/testdata/multi_level_namespace_test_with_allowlist/golden.md
@@ -1,27 +1,9 @@
<!-- Generated with Stardoc: http://skydoc.bazel.build -->
-A test that verifies documenting a multi-leveled namespace of functions with whitelist symbols.
-The whitelist symbols should cause everything in my_namespace to to be documented, but only a
+A test that verifies documenting a multi-leveled namespace of functions with allowlist symbols.
+The allowlist symbols should cause everything in my_namespace to to be documented, but only a
specific symbol in other_namespace to be documented.
-<a id="my_namespace.min"></a>
-
-## my_namespace.min
-
-<pre>
-my_namespace.min(<a href="#my_namespace.min-integers">integers</a>)
-</pre>
-
-Returns the minimum of given elements.
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="my_namespace.min-integers"></a>integers | <p align="center"> - </p> | none |
-
-
<a id="my_namespace.math.min"></a>
## my_namespace.math.min
@@ -40,6 +22,24 @@
| <a id="my_namespace.math.min-integers"></a>integers | <p align="center"> - </p> | none |
+<a id="my_namespace.min"></a>
+
+## my_namespace.min
+
+<pre>
+my_namespace.min(<a href="#my_namespace.min-integers">integers</a>)
+</pre>
+
+Returns the minimum of given elements.
+
+**PARAMETERS**
+
+
+| Name | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="my_namespace.min-integers"></a>integers | <p align="center"> - </p> | none |
+
+
<a id="other_namespace.foo.nothing"></a>
## other_namespace.foo.nothing
diff --git a/test/testdata/multi_level_namespace_test_with_whitelist/input.bzl b/test/testdata/multi_level_namespace_test_with_allowlist/input.bzl
similarity index 84%
rename from test/testdata/multi_level_namespace_test_with_whitelist/input.bzl
rename to test/testdata/multi_level_namespace_test_with_allowlist/input.bzl
index f070309..5146d11 100644
--- a/test/testdata/multi_level_namespace_test_with_whitelist/input.bzl
+++ b/test/testdata/multi_level_namespace_test_with_allowlist/input.bzl
@@ -1,5 +1,5 @@
-"""A test that verifies documenting a multi-leveled namespace of functions with whitelist symbols.
-The whitelist symbols should cause everything in my_namespace to to be documented, but only a
+"""A test that verifies documenting a multi-leveled namespace of functions with allowlist symbols.
+The allowlist symbols should cause everything in my_namespace to to be documented, but only a
specific symbol in other_namespace to be documented."""
def _min(integers):
diff --git a/test/testdata/namespace_test/golden.md b/test/testdata/namespace_test/golden.md
index f840fcf..850dcf1 100755
--- a/test/testdata/namespace_test/golden.md
+++ b/test/testdata/namespace_test/golden.md
@@ -21,28 +21,6 @@
| <a id="my_namespace.assert_non_empty-other_list"></a>other_list | The second list | none |
-<a id="my_namespace.min"></a>
-
-## my_namespace.min
-
-<pre>
-my_namespace.min(<a href="#my_namespace.min-integers">integers</a>)
-</pre>
-
-Returns the minimum of given elements.
-
-**PARAMETERS**
-
-
-| Name | Description | Default Value |
-| :------------- | :------------- | :------------- |
-| <a id="my_namespace.min-integers"></a>integers | A list of integers. Must not be empty. | none |
-
-**RETURNS**
-
-The minimum integer in the given list.
-
-
<a id="my_namespace.join_strings"></a>
## my_namespace.join_strings
@@ -66,3 +44,25 @@
The joined string.
+<a id="my_namespace.min"></a>
+
+## my_namespace.min
+
+<pre>
+my_namespace.min(<a href="#my_namespace.min-integers">integers</a>)
+</pre>
+
+Returns the minimum of given elements.
+
+**PARAMETERS**
+
+
+| Name | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="my_namespace.min-integers"></a>integers | A list of integers. Must not be empty. | none |
+
+**RETURNS**
+
+The minimum integer in the given list.
+
+
diff --git a/test/testdata/provider_basic_test/input.bzl b/test/testdata/provider_basic_test/input.bzl
index bb76c0d..959986f 100644
--- a/test/testdata/provider_basic_test/input.bzl
+++ b/test/testdata/provider_basic_test/input.bzl
@@ -18,3 +18,8 @@
"favorite_color": "A string representing my favorite color",
},
)
+
+named_providers_are_hashable = {
+ MyFooInfo: "MyFooInfo is hashable",
+ MyVeryDocumentedInfo: "So is MyVeryDocumentedInfo",
+}
diff --git a/test/testdata/pure_markdown_template_test/golden.md b/test/testdata/pure_markdown_template_test/golden.md
new file mode 100644
index 0000000..83a0e5c
--- /dev/null
+++ b/test/testdata/pure_markdown_template_test/golden.md
@@ -0,0 +1,92 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+Input file for markdown template test
+
+<a id="example_rule"></a>
+
+## example_rule
+
+<pre>
+example_rule(<a href="#example_rule-name">name</a>, <a href="#example_rule-first">first</a>, <a href="#example_rule-second">second</a>)
+</pre>
+
+Small example of rule using a markdown template.
+
+**ATTRIBUTES**
+
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="example_rule-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
+| <a id="example_rule-first"></a>first | This is the first attribute | String | optional | <code>""</code> |
+| <a id="example_rule-second"></a>second | - | String | optional | <code>"2"</code> |
+
+
+<a id="ExampleProviderInfo"></a>
+
+## ExampleProviderInfo
+
+<pre>
+ExampleProviderInfo(<a href="#ExampleProviderInfo-foo">foo</a>, <a href="#ExampleProviderInfo-bar">bar</a>, <a href="#ExampleProviderInfo-baz">baz</a>)
+</pre>
+
+Small example of provider using a markdown template.
+
+**FIELDS**
+
+
+| Name | Description |
+| :------------- | :------------- |
+| <a id="ExampleProviderInfo-foo"></a>foo | A string representing foo |
+| <a id="ExampleProviderInfo-bar"></a>bar | A string representing bar |
+| <a id="ExampleProviderInfo-baz"></a>baz | A string representing baz |
+
+
+<a id="example_function"></a>
+
+## example_function
+
+<pre>
+example_function(<a href="#example_function-foo">foo</a>, <a href="#example_function-bar">bar</a>)
+</pre>
+
+Small example of function using a markdown template.
+
+**PARAMETERS**
+
+
+| Name | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="example_function-foo"></a>foo | This parameter does foo related things. | none |
+| <a id="example_function-bar"></a>bar | This parameter does bar related things.<br><br>For example, it does things that require **multiple paragraphs** to explain.<br><br>Note: we should preserve the nested indent in the following code:<br><br><pre><code>json { "key": "value" } </code></pre> | <code>"bar"</code> |
+
+
+<a id="example_aspect"></a>
+
+## example_aspect
+
+<pre>
+example_aspect(<a href="#example_aspect-name">name</a>, <a href="#example_aspect-first">first</a>, <a href="#example_aspect-second">second</a>)
+</pre>
+
+Small example of aspect using a markdown template.
+
+**ASPECT ATTRIBUTES**
+
+
+| Name | Type |
+| :------------- | :------------- |
+| deps| String |
+| attr_aspect| String |
+
+
+**ATTRIBUTES**
+
+
+| Name | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="example_aspect-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
+| <a id="example_aspect-first"></a>first | - | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
+| <a id="example_aspect-second"></a>second | This is the second attribute. | String | optional | <code>""</code> |
+
+
diff --git a/test/testdata/pure_markdown_template_test/input.bzl b/test/testdata/pure_markdown_template_test/input.bzl
new file mode 100644
index 0000000..814acdd
--- /dev/null
+++ b/test/testdata/pure_markdown_template_test/input.bzl
@@ -0,0 +1,57 @@
+"""Input file for markdown template test"""
+
+# buildifier: disable=unused-variable
+def example_function(foo, bar = "bar"):
+ """Small example of function using a markdown template.
+
+ Args:
+ foo: This parameter does foo related things.
+ bar: This parameter does bar related things.
+
+ For example, it does things that require **multiple paragraphs** to explain.
+
+ Note: we should preserve the nested indent in the following code:
+
+ ```json
+ {
+ "key": "value"
+ }
+ ```
+ """
+ pass
+
+ExampleProviderInfo = provider(
+ doc = "Small example of provider using a markdown template.",
+ fields = {
+ "foo": "A string representing foo",
+ "bar": "A string representing bar",
+ "baz": "A string representing baz",
+ },
+)
+
+# buildifier: disable=unused-variable
+def _rule_impl(ctx):
+ return []
+
+example_rule = rule(
+ implementation = _rule_impl,
+ doc = "Small example of rule using a markdown template.",
+ attrs = {
+ "first": attr.string(doc = "This is the first attribute"),
+ "second": attr.string(default = "2"),
+ },
+)
+
+# buildifier: disable=unused-variable
+def _aspect_impl(ctx):
+ return []
+
+example_aspect = aspect(
+ implementation = _aspect_impl,
+ doc = "Small example of aspect using a markdown template.",
+ attr_aspects = ["deps", "attr_aspect"],
+ attrs = {
+ "first": attr.label(mandatory = True, allow_single_file = True),
+ "second": attr.string(doc = "This is the second attribute."),
+ },
+)
diff --git a/test/testdata/repo_rules_test/golden.md b/test/testdata/repo_rules_test/golden.md
index 87391e3..da8a1ba 100755
--- a/test/testdata/repo_rules_test/golden.md
+++ b/test/testdata/repo_rules_test/golden.md
@@ -19,6 +19,6 @@
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <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 | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.<p>For example, an entry <code>"@foo": "@bar"</code> declares that, for any time this repository depends on <code>@foo</code> (such as a dependency on <code>@foo//some:target</code>, it should actually resolve that dependency within globally-declared <code>@bar</code> (<code>@bar//some:target</code>). | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
-| <a id="my_repo-useless"></a>useless | This argument will be ingored. You don't have to specify it, but you may. | String | optional | <code>"ignoreme"</code> |
+| <a id="my_repo-useless"></a>useless | This argument will be ignored. You don't have to specify it, but you may. | String | optional | <code>"ignoreme"</code> |
diff --git a/test/testdata/repo_rules_test/input.bzl b/test/testdata/repo_rules_test/input.bzl
index 023d92d..aca64f8 100644
--- a/test/testdata/repo_rules_test/input.bzl
+++ b/test/testdata/repo_rules_test/input.bzl
@@ -7,7 +7,7 @@
doc = "Minimal example of a repository rule.",
attrs = {
"useless": attr.string(
- doc = "This argument will be ingored. You don't have to specify it, but you may.",
+ doc = "This argument will be ignored. You don't have to specify it, but you may.",
default = "ignoreme",
),
},
diff --git a/update-release-binary.sh b/update-release-binary.sh
index 1423fbf..bf1307a 100755
--- a/update-release-binary.sh
+++ b/update-release-binary.sh
@@ -28,15 +28,6 @@
echo "** Stardoc copied."
-echo "** Building Renderer from source..."
-bazel build --java_language_version=11 @io_bazel//src/main/java/com/google/devtools/build/skydoc/renderer:renderer_deploy.jar
-
-echo "** Copying Renderer binary..."
-cp bazel-bin/external/io_bazel/src/main/java/com/google/devtools/build/skydoc/renderer/renderer_deploy.jar \
- stardoc/renderer_binary.jar
-
-echo "** Renderer copied."
-
echo "** Copying stardoc_output.proto from source..."
cp $(bazel info output_base)/external/io_bazel/src/main/java/com/google/devtools/build/skydoc/rendering/proto/stardoc_output.proto stardoc/proto/stardoc_output.proto
echo "** stardoc_output.proto copied."