Snap for 7862349 from 64d517f6321fa5674a832e085724929acdc3cb55 to t-keystone-qcom-release

Change-Id: I4f353fe6109c60ad07c47ad83a7d83b1a0f35c57
diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
new file mode 100644
index 0000000..a4dd49c
--- /dev/null
+++ b/.bazelci/presubmit.yml
@@ -0,0 +1,24 @@
+---
+platforms:
+  ubuntu1604:
+    build_targets:
+    - "..."
+    test_targets:
+    - "..."
+  ubuntu1804:
+    build_targets:
+    - "..."
+    test_targets:
+    - "..."
+  macos:
+    build_targets:
+    - "..."
+    test_targets:
+    - "..."
+  windows:
+    build_targets:
+    - "..."
+    test_targets:
+    - "..."
+
+buildifier: latest
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a7f7d95
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,19 @@
+*~
+.*.swp
+/.classpath
+/.factorypath
+/.idea/
+/.ijwb/
+/.project
+/.settings
+/WORKSPACE.user.bzl
+/base_workspace/*
+/bazel-stardoc
+/bazel-bin
+/bazel-genfiles
+/bazel-out
+/bazel-testlogs
+/bazel.iml
+/output/
+/production
+/.sass-cache
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..8f95963
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,9 @@
+# This the official list of Bazel authors for copyright purposes.
+# This file is distinct from the CONTRIBUTORS files.
+# See the latter for an explanation.
+
+# Names should be added to this file as:
+# Name or Organization <email address>
+# The email address is not required for organizations.
+
+Google Inc.
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..c8dedb1
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,10 @@
+licenses(["notice"])
+
+exports_files(["LICENSE"])
+
+filegroup(
+    name = "stardoc_rule_doc",
+    testonly = 1,
+    srcs = ["docs/stardoc_rule.md"],
+    visibility = ["//test:__pkg__"],
+)
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 0000000..d7feba7
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1 @@
+* @c-parsons @laurentlb @jin
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..035bbca
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,27 @@
+Want to contribute? Great! First, read this page (including the small print at the end).
+
+### Before you contribute
+**Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1)
+(CLA)**, which you can do online.
+
+The CLA is necessary mainly because you own the copyright to your changes,
+even after your contribution becomes part of our codebase, so we need your
+permission to use and distribute your code. We also need to be sure of
+various other things — for instance that you'll tell us if you know that
+your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+
+Before you start working on a larger contribution, you should get in touch
+with us first. Use the issue tracker to explain your idea so we can help and
+possibly guide you.
+
+### Code reviews and other contributions.
+**All submissions, including submissions by project members, require review.**
+Please follow the instructions in [the contributors documentation](https://bazel.build/contributing.html).
+
+### The small print
+Contributions made by corporations are covered by a different agreement than
+the one above, the
+[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate).
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
index 0000000..c186cc2
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,15 @@
+# People who have agreed to one of the CLAs and can contribute patches.
+# The AUTHORS file lists the copyright holders; this file
+# lists people.  For example, Google employees are listed here
+# but not in AUTHORS, because Google holds the copyright.
+#
+# https://developers.google.com/open-source/cla/individual
+# https://developers.google.com/open-source/cla/corporate
+#
+# Names should be added to this file as:
+#     Name <email address>
+
+Jon Brandvein <brandjon@google.com>
+Chris Parsons <cparsons@google.com>
+Jingwen Chen <jingwen@google.com>
+Laurent Le Brun <laurentlb@google.com>
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..9e6559f
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,6 @@
+include platform/build/bazel:/OWNERS
+
+# Kleaf
+# https://android.googlesource.com/kernel/build/+/refs/heads/master/kleaf/README.md
+elsk@google.com
+maennich@google.com
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5cff3d9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,30 @@
+# Stardoc - Starlark Documentation Generator
+
+[![Build status](https://badge.buildkite.com/d8594eb71e4869c792cce22428b08e03b345f9c65dc603d70b.svg?branch=master)](https://buildkite.com/bazel/stardoc)
+
+Stardoc is a documentation generator for [Bazel](https://bazel.build) build rules
+written in [Starlark](https://bazel.build/docs/skylark/index.html).
+
+Stardoc provides a Starlark rule (`stardoc`, see [documentation](docs/stardoc_rule.md)) that can
+be used to build documentation for Starlark rules in Markdown. Stardoc generates one documentation
+page per `.bzl`file.
+
+## Get Started
+
+* How to [set up Stardoc for your project](docs/getting_started_stardoc.md)
+* Writing [docstrings](docs/writing_stardoc.md)
+* How to [integrate Stardoc with your build](docs/generating_stardoc.md).
+* See also [Advanced Topics](docs/advanced_stardoc_usage.md).
+
+## About Stardoc
+
+* Stardoc [rule reference](docs/stardoc_rule.md).
+* How to [contribute to Stardoc](docs/contributing.md)
+
+## Skydoc deprecation
+
+Stardoc is a replacement for the **deprecated** "Skydoc" documentation generator.
+
+See [Skydoc Deprecation](docs/skydoc_deprecation.md) for
+details on the deprecation and migration details.
+
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..3de48c9
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,70 @@
+workspace(name = "io_bazel_skydoc")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load(":setup.bzl", "stardoc_repositories")
+
+stardoc_repositories()
+
+#######################################################################
+##### MOST USERS SHOULD NOT NEED TO COPY ANYTHING BELOW THIS LINE #####
+#######################################################################
+load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
+
+# Needed for generating the Stardoc release binary.
+git_repository(
+    name = "io_bazel",
+    commit = "5eeccd8a647df10d154d3b86e9732e7f263c96db",  # Oct 7, 2019
+    remote = "https://github.com/bazelbuild/bazel.git",
+)
+
+# Needed only because of java_tools.
+http_archive(
+    name = "rules_cc",
+    sha256 = "36fa66d4d49debd71d05fba55c1353b522e8caef4a20f8080a3d17cdda001d89",
+    strip_prefix = "rules_cc-0d5f3f2768c6ca2faca0079a997a97ce22997a0c",
+    urls = [
+        "https://mirror.bazel.build/github.com/bazelbuild/rules_cc/archive/0d5f3f2768c6ca2faca0079a997a97ce22997a0c.zip",
+        "https://github.com/bazelbuild/rules_cc/archive/0d5f3f2768c6ca2faca0079a997a97ce22997a0c.zip",
+    ],
+)
+
+# Needed as a transitive dependency of @io_bazel
+git_repository(
+    name = "com_google_protobuf",
+    commit = "7b28271a61a3da0a37f6fda399b0c4c86464e5b3",  # 2018-11-16
+    remote = "https://github.com/protocolbuffers/protobuf.git",
+)
+
+# Needed as a transitive dependency of @io_bazel
+git_repository(
+    name = "rules_python",
+    remote = "https://github.com/bazelbuild/rules_python.git",
+    commit = "4b84ad270387a7c439ebdccfd530e2339601ef27",
+)
+
+# Needed as a transitive dependency of @io_bazel
+http_archive(
+    name = "rules_pkg",
+    sha256 = "5bdc04987af79bd27bc5b00fe30f59a858f77ffa0bd2d8143d5b31ad8b1bd71c",
+    urls = [
+        "https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/rules_pkg-0.2.0.tar.gz",
+        "https://github.com/bazelbuild/rules_pkg/releases/download/0.2.0/rules_pkg-0.2.0.tar.gz",
+    ],
+)
+
+# Needed as a transitive dependency of @io_bazel
+http_archive(
+    name = "rules_proto",
+    sha256 = "88b0a90433866b44bb4450d4c30bc5738b8c4f9c9ba14e9661deb123f56a833d",
+    strip_prefix = "rules_proto-b0cc14be5da05168b01db282fe93bdf17aa2b9f4",
+    urls = [
+        "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/b0cc14be5da05168b01db282fe93bdf17aa2b9f4.tar.gz",
+        "https://github.com/bazelbuild/rules_proto/archive/b0cc14be5da05168b01db282fe93bdf17aa2b9f4.tar.gz",
+    ],
+)
+
+# Needed only for testing stardoc across local-repository bounds.
+local_repository(
+    name = "local_repository_test",
+    path = "test/testdata/local_repository_test",
+)
diff --git a/docs/advanced_stardoc_usage.md b/docs/advanced_stardoc_usage.md
new file mode 100644
index 0000000..ce3c069
--- /dev/null
+++ b/docs/advanced_stardoc_usage.md
@@ -0,0 +1,87 @@
+<nav class="toc">
+  <h2>Contents</h2>
+  <ul>
+    <li><a href="#docstring-formatting">Docstring Formatting</a></li>
+    <li><a href="#custom-output">Custom Output</a></li>
+  </ul>
+</nav>
+
+This document covers a number of advanced topics pertaining to using Stardoc.
+
+
+<a name="docstring-formatting"></a>
+## Docstring Formatting
+
+You may want to inline various kinds of formatting in the docstrings adjacent
+to your Starlark code. Use standard markdown formatting constructs instead of
+HTML tags.
+
+For example:
+```python
+def my_function(foo, bar):
+  """Does some cool stuff.
+
+  Oh, by the way, have you heard about [Stardoc](https://github.com/bazelbuild/stardoc)?
+
+  Args:
+    foo: You don't know what a **foo** is?
+    bar: Two variables, `x` and `y`, walk in to a bar...
+  """
+  ...
+```
+
+Markdown formatting constructs are handled appropriately by Stardoc's default
+output format ("markdown_tables"), even as part of a table.
+
+
+<a name="custom-output"></a>
+## Custom Output
+
+Stardoc's output format is customizable; while Stardoc's output is markdown
+by default, you may define a different output format for your documentation.
+
+Customization is done at the level of "output templates". To customize the
+doc output for a particular type of Starlark definition (such as a "rule" or a
+"function"), you will need to:
+
+1. Create a new custom output template to describe how this type of object should
+   be rendered.
+2. In your `stardoc()` target, set the matching `_template` attribute to point to
+   your new output template.
+
+For example, you might want to change the way rule documentation is generated.
+You might create a new output template file `package/rule.vm` and then define your
+`stardoc` target as follows:
+
+```python
+stardoc(
+    name = "my_docs",
+    input = "my_rule.bzl",
+    out = "my_rule_doc.md",
+    rule_template = "//package:rule.vm",
+)
+```
+
+The default values for the available templates may be found under
+[templates/markdown_tables](../stardoc/templates/markdown_tables). See the
+[Stardoc rule documentation](stardoc_rule.md) for a comprehensive list of which
+'_template' attributes are available.
+
+
+### Writing a custom output template
+
+Stardoc's output templates are defined using
+[Velocity Template Language (VTL)](https://velocity.apache.org/engine/1.7/user-guide.html)
+with utilities and model objects available in the evaluation context.
+
+The full comprehensive list of available utilities top-level objects is available in
+[the source for MarkdownRenderer](https://github.com/bazelbuild/bazel/blob/3fcfbe14ddec34889c5e3fe33415af2cf9124e7c/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java#L100).
+
+Information available for raw model objects (such rule information) is defined by
+Stardoc's underlying [proto schema](https://github.com/bazelbuild/bazel/blob/5eeccd8a647df10d154d3b86e9732e7f263c96db/src/main/java/com/google/devtools/build/skydoc/rendering/proto/stardoc_output.proto).
+
+This is a particularly advanced feature of Stardoc, so we would recommend using
+one of the existing canonical [templates](../stardoc/templates/markdown_tables) as a
+springboard to get started.
+
+
diff --git a/docs/contributing.md b/docs/contributing.md
new file mode 100644
index 0000000..e28b11d
--- /dev/null
+++ b/docs/contributing.md
@@ -0,0 +1,52 @@
+We welcome your contributions! To contribute to Stardoc, fork the
+[Stardoc](https://github.com/bazelbuild/stardoc) GitHub repository and start
+submitting pull requests.
+
+In general, we prefer contributions that fix bugs or add features (as opposed to
+purely stylistic, refactoring, or "cleanup" changes). Please check with us by
+opening a [GitHub Issue](https://github.com/bazelbuild/stardoc/issues) or emailing the
+[bazel-dev](https://groups.google.com/forum/#!forum/bazel-dev) mailing list.
+
+## Stardoc code structure
+
+* The [bazelbuild/stardoc](https://github.com/bazelbuild/stardoc) repository
+  contains Stardoc's Starlark code alongside Stardoc's prebuilt java binaries (jars).
+* The source code for Stardoc's jars can be found under the bazelbuild/bazel source tree
+  [here](https://github.com/bazelbuild/bazel/tree/master/src/main/java/com/google/devtools/build/skydoc).
+  Changes to Stardoc's java binaries will thus require creation of pull requests to the
+  [bazelbuild/bazel](https://github.com/bazelbuild/bazel) repository.
+* Changes to Stardoc's source are pulled in by updating bazelbuild/stardoc's dependency
+  on the bazel source tree and and then rebuilding the binary using bazel. This process
+  is done periodically by Stardoc's [core contributors](#core-contributors) (generally
+  with large changes to Stardoc source, and right before cutting a new Stardoc release).
+
+## Contributing to Stardoc
+
+* Stardoc is part of the Bazel project. Read the [Bazel governance
+  plan](https://www.bazel.build/governance.html) and Stardoc's [contribution
+  guidelines](../CONTRIBUTING.md).
+* Open an [Issue](https://github.com/bazelbuild/stardoc/issues) or discuss your
+  plan or design on the [bazel-dev](https://groups.google.com/forum/#!forum/bazel-dev)
+  mailing list.
+* Prepare a Git commit that implements your feature or bug fix. Don't forget to
+  add tests and reference the corresponding bug, if any.
+* Open a [Pull Request](https://github.com/bazelbuild/stardoc/pulls) on the Stardoc
+  repository. This will require that you have signed a
+  [Contributor License Agreement](https://cla.developers.google.com/).
+* Complete a code review with a [core contributor](#core-contributors). Amend your
+  patch by making additional commits or rebasing with HEAD if there are conflicts with new
+  commits on the master branch.
+* Once the code review is complete, your reviewer will squash/merge your pull
+  request to the master branch.
+
+## Core Contributors
+
+The current group of Stardoc core contributors are:
+
+* [brandjon](https://github.com/brandjon)
+* [cparsons](https://github.com/c-parsons)
+* [jin](https://github.com/jin)
+* [laurentlb](https://github.com/laurentlb)
+
+
+
diff --git a/docs/generating_stardoc.md b/docs/generating_stardoc.md
new file mode 100644
index 0000000..88a37bd
--- /dev/null
+++ b/docs/generating_stardoc.md
@@ -0,0 +1,163 @@
+<nav class="toc">
+  <h2>Contents</h2>
+  <ul>
+    <li><a href="#single-file">Single File</a></li>
+    <li><a href="#files-with-deps">Files with Dependencies</a></li>
+    <li><a href="#multiple-files">Multiple Files</a></li>
+  </ul>
+</nav>
+
+The following are some examples of how to use Stardoc.
+
+<a name="single-file"></a>
+## Single File
+
+Suppose you have a project containing Stardoc rules you want to document:
+
+```
+[workspace]/
+    WORKSPACE
+    checkstyle/
+        BUILD
+        checkstyle.bzl
+```
+
+To generate documentation for the rules in `checkstyle.bzl`, add the
+following target to `rules/BUILD`:
+
+```python
+load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc")
+
+stardoc(
+    name = "checkstyle-docs",
+    input = "checkstyle.bzl",
+    out = "checkstyle_doc.md",
+)
+```
+
+Running `bazel build //checkstyle:checkstyle-docs` will generate a markdown file
+containing documentation for all Starlark rules defined in `checkstyle.bzl`.
+
+To generate a subset of rules defined in `checkstyle.bzl`, you may specify which
+rule names you specifically want documentation for using the `symbol_names` attribute
+of the `stardoc` rule. If `symbol_names` is specified, only rules matching a name
+in `symbol_names` will be documented:
+
+```python
+load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc")
+
+stardoc(
+    name = "checkstyle-docs",
+    input = "checkstyle.bzl",
+    out = "checkstyle_doc.md",
+    symbol_names = ["checkstyle_rule", "other_rule"],
+)
+```
+
+<a name="files-with-deps"></a>
+## Files with Dependencies
+
+If you would like to generate documentation for a `.bzl` with dependencies on
+other `.bzl` files, use the `bzl_library` rule to create logical collections of
+Starlark sources and depend on these libraries via the `deps` attribute of your
+`stardoc` target.
+
+Suppose your project has the following structure:
+
+```
+[workspace]/
+    WORKSPACE
+    BUILD
+    checkstyle/
+        BUILD
+        checkstyle.bzl
+    lua/
+        BUILD
+        lua.bzl
+        luarocks.bzl
+```
+
+...and suppose your target `.bzl` file depends on other `.bzl` files in your workspace:
+
+`checkstyle/checkstyle.bzl`:
+
+```python
+load("//lua:lua.bzl", "lua_utility")
+
+lua_utility()
+
+checkstyle_rule = rule(
+    ...
+)
+```
+
+In this case, you can have a `bzl_library` target in `lua/BUILD`:
+
+`lua/BUILD`:
+
+```python
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+bzl_library(
+    name = "lua-rules",
+    srcs = [
+        "lua.bzl",
+        "luarocks.bzl",
+    ],
+)
+```
+
+To build documentation for `checkstyle.bzl`, specify the `bzl_library` target
+as a dependency of the `stardoc` target:
+
+`checkstyle/BUILD`:
+
+```python
+load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc")
+
+stardoc(
+    name = "checkstyle-docs",
+    input = "checkstyle.bzl",
+    out = "checkstyle_doc.md",
+    deps = ["//lua:lua-rules"],
+)
+```
+
+<a name="multiple-files"></a>
+## Multiple Files
+
+If you would like to generate documentation for multiple .bzl files in various
+packages in your workspace, you will need to create a single `.bzl` file that depends
+on all those `.bzl` files. You can then explicitly whitelist rules for which you would
+like documentation to be generated.
+
+For example, you may want to generate documentation for `foo_rule`, `bar_rule`, and
+`baz_rule`, all in different `.bzl` files. First, you would create a single `.bzl` file
+which loads these files:
+
+`doc_hub.bzl`:
+
+```python
+load("//foo:foo.bzl", "foo_rule")
+load("//bar:bar.bzl", "bar_rule")
+load("//baz:baz.bzl", "baz_rule")
+
+# No need for any implementation here. The rules need only be loaded.
+```
+
+A single `stardoc` target can then be used to generate their documentation:
+
+`BUILD`:
+
+```python
+load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc")
+
+stardoc(
+    name = "my-docs",
+    input = "doc_hub.bzl",
+    out = "docs.md",
+    symbol_names = ["foo_rule", "bar_rule", "baz_rule"],
+)
+```
+
+
diff --git a/docs/getting_started_stardoc.md b/docs/getting_started_stardoc.md
new file mode 100644
index 0000000..f40669e
--- /dev/null
+++ b/docs/getting_started_stardoc.md
@@ -0,0 +1,41 @@
+Stardoc is a documentation generator for [Bazel](https://bazel.build) build rules
+written in [Starlark](https://bazel.build/docs/skylark/index.html).
+
+Stardoc provides a Starlark rule (`stardoc`)
+that can be used to build Markdown documentation for Starlark rules, providers,
+and functions.
+Starlark generates one documentation page per `stardoc` target.
+
+If you are new to writing build rules for Bazel, please read the Bazel
+documentation on [writing
+extensions](https://www.bazel.build/docs/skylark/concepts.html)
+
+## Setup
+
+To use Stardoc, add the following to your `WORKSPACE` file:
+
+```python
+load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
+
+git_repository(
+    name = "io_bazel_stardoc",
+    remote = "https://github.com/bazelbuild/stardoc.git",
+    tag = "0.4.0",
+)
+
+load("@io_bazel_stardoc//:setup.bzl", "stardoc_repositories")
+stardoc_repositories()
+```
+
+The load statement and function call after the `io_bazel_stardoc` repository
+definition ensure that this repository's dependencies are loaded.
+
+## Next Steps
+
+Now you are ready to document your Starlark rules.
+
+* Learn about the [docstring format](writing_stardoc.md) used to document Starlark rules.
+* Learn about how you can use Stardoc's [build rules](generating_stardoc.md) to generate your
+  documentation in Markdown format.
+
+
diff --git a/docs/skydoc_deprecation.md b/docs/skydoc_deprecation.md
new file mode 100644
index 0000000..3ad957b
--- /dev/null
+++ b/docs/skydoc_deprecation.md
@@ -0,0 +1,137 @@
+## Why was Skydoc deprecated?
+
+Skydoc functioned by evaluating Starlark files as if they were Python. Unfortunately, while
+Starlark is **similar** to Python, there are some important syntactic differences between
+the languages. Assuming compatibility between the languages was inherently brittle, and resulted
+in a maintenance burden on the Starlark code. Specifically, if one of your transitive dependencies
+were to adopt a Starlark-compatible, Python-incompatible construct, your Skydoc integration would
+break!
+
+Skydoc still exists under [bazelbuild/skydoc](https://github.com/bazelbuild/skydoc), as it's a
+nontrivial migration to Stardoc, but Skydoc is completely unsupported as of September 2019.
+The [bazelbuild/skydoc](https://github.com/bazelbuild/skydoc) will be archived by end of 2019.
+
+## How to migrate
+
+Stardoc is not a drop-in replacement for Skydoc. Its usage is slightly different, and it has some
+new features. It's recommended to take a look at the root Stardoc documentation, but here is
+a brief summary of some things to note for migration:
+
+### Docstring specification
+
+Stardoc uses inline documentation strings instead of Python-style docstrings.
+For example, Skydoc documentation may have been specified with:
+
+```python
+my_rule = rule(
+    implementation = _my_rule_impl,
+    attrs = {
+        "srcs": attr.label_list(),
+        "deps": attr.label_list(),
+    },
+)
+"""Example rule documentation.
+
+Example:
+  Here is an example of how to use this rule.
+
+Args:
+  srcs: Source files used to build this target.
+  deps: Dependencies for this target.
+"""
+```
+
+...the equivalent for Stardoc is:
+
+```python
+my_rule = rule(
+    implementation = _my_rule_impl,
+    doc = """
+Example rule documentation.
+
+Example:
+  Here is an example of how to use this rule.
+""",
+    attrs = {
+        "srcs" : attr.label_list(
+            doc = "Source files used to build this target.",
+        ),
+        "deps" : attr.label_list(
+            doc = "Dependencies for this target.",
+        ),
+    }
+)
+```
+
+### Different Starlark Rule
+
+Stardoc uses a different Starlark rule than Skydoc with different attributes.
+
+See [Generating Documentation](generating_stardoc.md) for a
+tutorial on using the new rule, and the
+[Build Rule Reference](docs/stardoc_reference.md) for information
+about the new `stardoc` rule itself.
+
+### Starlark Dependencies
+
+Stardoc depends on your `bzl` file, all of its dependencies, and all of its **transitive**
+dependencies, so that it can fully evaluate your Starlark code.
+`bazel-skylib`'s `bzl_library` is the recommend approach for tracking `bzl` dependencies.
+
+For example, suppose your `mypackage/foo.bzl` file depends on `other/package/bar.bzl`, which
+depends on `third/package/baz.bzl`.
+
+**BUILD**:
+
+```python
+load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc")
+
+stardoc(
+    name = "foo_docs",
+    input = "foo.bzl",
+    out = "foo_doc.md",
+    deps = ["//other/package:bar"],
+)
+```
+
+**other/package/BUILD**:
+
+```python
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+bzl_library(
+    name = "bar",
+    srcs = ["bar.bzl"],
+    deps = ["//third/package:baz"],
+)
+```
+
+**third/package/BUILD**:
+
+```python
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+bzl_library(
+    name = "baz",
+    srcs = ["baz.bzl"],
+)
+```
+
+Thus, each `.bzl` file should appear in the `srcs` of a `bzl_library` target defined in the same
+package. The `deps` of this `bzl_library` should be (only) the `bzl_library` targets corresponding
+to the files that are _directly_ `load()`ed by the `srcs`. This structure mirrors that of other
+`<language>_library` rules in Bazel.
+
+This migration might involve creating a large number of new `bzl_library` targets,
+but this work is useful beyond Stardoc. For example, `bzl_library` can be also used to gather
+transitive Starlark dependencies for use in shell tests or other test frameworks.
+
+See [Generating Documentation](docs/generating_stardoc.md) for
+a tutorial.
+
+## Migration Issues
+
+If you run into any issues migrating, please file a
+[GitHub issue](https://github.com/bazelbuild/stardoc/issues).
+
+
diff --git a/docs/stardoc_rule.md b/docs/stardoc_rule.md
new file mode 100644
index 0000000..71200a0
--- /dev/null
+++ b/docs/stardoc_rule.md
@@ -0,0 +1,38 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#stardoc"></a>
+
+## stardoc
+
+<pre>
+stardoc(<a href="#stardoc-name">name</a>, <a href="#stardoc-aspect_template">aspect_template</a>, <a href="#stardoc-deps">deps</a>, <a href="#stardoc-format">format</a>, <a href="#stardoc-func_template">func_template</a>, <a href="#stardoc-header_template">header_template</a>, <a href="#stardoc-input">input</a>, <a href="#stardoc-out">out</a>,
+        <a href="#stardoc-provider_template">provider_template</a>, <a href="#stardoc-renderer">renderer</a>, <a href="#stardoc-rule_template">rule_template</a>, <a href="#stardoc-semantic_flags">semantic_flags</a>, <a href="#stardoc-stardoc">stardoc</a>, <a href="#stardoc-symbol_names">symbol_names</a>)
+</pre>
+
+
+Generates documentation for exported skylark rule definitions in a target starlark file.
+
+This rule is an experimental replacement for the existing skylark_doc rule.
+
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| aspect_template |  The input file template for generating documentation of aspects.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | //stardoc:templates/markdown_tables/aspect.vm |
+| deps |  A list of skylark_library dependencies which the input depends on.   | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
+| format |  The format of the output file. Valid values: 'markdown' or 'proto'.   | String | optional | "markdown" |
+| func_template |  The input file template for generating documentation of functions.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | //stardoc:templates/markdown_tables/func.vm |
+| header_template |  The input file template for the header of the output documentation.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | //stardoc:templates/markdown_tables/header.vm |
+| input |  The starlark file to generate documentation for.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
+| out |  The (markdown) file to which documentation will be output.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| provider_template |  The input file template for generating documentation of providers.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | //stardoc:templates/markdown_tables/provider.vm |
+| renderer |  The location of the renderer tool.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | //stardoc:renderer |
+| rule_template |  The input file template for generating documentation of rules.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | //stardoc:templates/markdown_tables/rule.vm |
+| semantic_flags |  A list of canonical flags to affect Starlark semantics for the Starlark interpretter during documentation generation. This should only be used to maintain compatibility with non-default semantic flags required to use the given Starlark symbols.<br><br>For example, if <code>//foo:bar.bzl</code> does not build except when a user would specify <code>--incompatible_foo_semantic=false</code>, then this attribute should contain "--incompatible_foo_semantic=false".   | List of strings | optional | [] |
+| stardoc |  The location of the stardoc tool.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | //stardoc:stardoc |
+| symbol_names |  A list of symbol names to generate documentation for. These should correspond to the names of rule definitions in the input file. If this list is empty, then documentation for all exported rule definitions will be generated.   | List of strings | optional | [] |
+
+
diff --git a/docs/writing_stardoc.md b/docs/writing_stardoc.md
new file mode 100644
index 0000000..6a042c2
--- /dev/null
+++ b/docs/writing_stardoc.md
@@ -0,0 +1,122 @@
+<nav class="toc">
+  <h2>Contents</h2>
+  <ul>
+    <li><a href="#rule-documentation">Rule Documentation</a></li>
+    <li><a href="#provider-documentation">Provider Documentation</a></li>
+    <li><a href="#macro-documentation">Macro / Function Documentation</a></li>
+  </ul>
+</nav>
+
+When generating documentation, Stardoc parses the `.bzl` file to extract the
+inline documentation as well as evaluates the Starlark code to determine the
+types for rule attributes. Stardoc will, by default, generate documentation for
+all rules, macros, and functions reachable from a target `.bzl` file.
+See [Generating Stardoc](generating_stardoc.md) for details on limiting the
+symbols for which stardoc generates documentation.
+
+<a name="rule-documentation"></a>
+## Rule Documentation
+
+When generating documentation, Stardoc parses the `.bzl` file to extract the
+inline documentation as well as evaluates the Starlark code to determine the
+types for rule attributes.
+
+Private rule attributes (attributes with names that begin with `_`) will not
+appear in generated documentation.
+
+[Starlark Rules](https://bazel.build/docs/skylark/rules.html) are declared using
+the `rule()` function as global variables.
+
+General rule documentation should be supplied in the `doc` parameter of the
+`rule()` function.
+
+Likewise, supply attribute documentation in the `doc` parameter of attribute
+schema-defining functions, such as `attr.label()`.
+
+```python
+my_rule = rule(
+    implementation = _my_rule_impl,
+    doc = """
+Example rule documentation.
+
+Example:
+  Here is an example of how to use this rule.
+""",
+    attrs = {
+        "srcs" : attr.label_list(
+            doc = "Source files used to build this target.",
+        ),
+        "deps" : attr.label_list(
+            doc = "Dependencies for this target.",
+        ),
+    }
+)
+```
+
+The `name` attribute that is common to all rules is documented by default.
+
+<a name="provider-documentation"></a>
+## Provider Documentation
+
+[Starlark Providers](https://docs.bazel.build/versions/master/skylark/rules.html#providers)
+are documented similarly to rules: using docstrings specified as parameters during
+creation of the provider.
+
+General provider documentation can be specified using the `doc` parameter
+to the `provider()` function.
+
+Field-related documentation can be specified by passing a map to the
+`fields` parameter of the `provider()` function. Keys are required field
+names, and values are their corresponding docstrings.
+
+```python
+MyInfo = provider(
+    doc = """
+A provider with some really neat documentation.
+
+Contains information about some of my favorite things.
+""",
+    fields = {'favorite_food' : 'A string representing my favorite food',
+              'favorite_color' : 'A string representing my favorite color'}
+)
+```
+
+<a name="macro-documentation"></a>
+## Macro / Function Documentation
+
+Functions and [Starlark Macros](https://bazel.build/docs/skylark/macros.html) are documented
+using docstrings similar to Python docstring format:
+
+```python
+def rat_check(name, srcs=[], format, visibility):
+  """Runs Apache Rat license checks on the given source files.
+
+  This rule runs [Apache Rat](http://creadur.apache.org/rat/) license checks on
+  a given set of source files. Use `bazel build` to run the check.
+
+  Args:
+    name: A unique name for this rule.
+    srcs: Source files to run the Rat license checks against.
+
+      Note that the Bazel glob() function can be used to specify which source
+      files to include and which to exclude.
+    format: The format to write the Rat check report in.
+    visibility: The visibility of this rule.
+  """
+  if format not in ['text', 'html', 'xml']:
+    fail('Invalid format: %s' % format, 'format')
+
+  _rat_check(
+      name = name,
+      srcs = srcs,
+      format = format,
+      visibility = visibility,
+  )
+```
+
+Parameters are documented in a special `Args:` section. Begin the documentation
+for each parameter on an indented line with the parameter name followed by a
+colon `:`. The documentation for a parameter can span multiple lines as long as
+each line is indented from the first line.
+
+
diff --git a/setup.bzl b/setup.bzl
new file mode 100644
index 0000000..5c8c119
--- /dev/null
+++ b/setup.bzl
@@ -0,0 +1,40 @@
+# 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.
+
+"""Repository external dependency resolution functions."""
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+def _include_if_not_defined(repo_rule, name, **kwargs):
+    if not native.existing_rule(name):
+        repo_rule(name = name, **kwargs)
+
+def stardoc_repositories():
+    """Adds the external repositories used by the Starlark rules."""
+    _include_if_not_defined(
+        http_archive,
+        name = "bazel_skylib",
+        urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/0.8.0/bazel-skylib.0.8.0.tar.gz"],
+        sha256 = "2ef429f5d7ce7111263289644d233707dba35e39696377ebab8b0bc701f7818e",
+    )
+    _include_if_not_defined(
+        http_archive,
+        name = "rules_java",
+        urls = [
+            "https://mirror.bazel.build/github.com/bazelbuild/rules_java/archive/7cf3cefd652008d0a64a419c34c13bdca6c8f178.zip",
+            "https://github.com/bazelbuild/rules_java/archive/7cf3cefd652008d0a64a419c34c13bdca6c8f178.zip",
+        ],
+        sha256 = "bc81f1ba47ef5cc68ad32225c3d0e70b8c6f6077663835438da8d5733f917598",
+        strip_prefix = "rules_java-7cf3cefd652008d0a64a419c34c13bdca6c8f178",
+    )
diff --git a/stardoc/BUILD b/stardoc/BUILD
new file mode 100644
index 0000000..a67873e
--- /dev/null
+++ b/stardoc/BUILD
@@ -0,0 +1,81 @@
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+exports_files(glob(["templates/**"]))
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load("//stardoc:stardoc.bzl", "stardoc")
+load("@rules_java//java:defs.bzl", "java_binary", "java_import")
+
+filegroup(
+    name = "test_deps",
+    testonly = True,
+    srcs = [
+        "BUILD",
+    ] + glob(["*.bzl"]),
+    visibility = ["//visibility:public"],
+)
+
+bzl_library(
+    name = "stardoc_lib",
+    srcs = ["stardoc.bzl"],
+    deps = [
+        "@bazel_skylib//:bzl_library",
+    ],
+    visibility = ["//visibility:public"],
+)
+
+stardoc(
+    name = "stardoc_doc",
+    out = "stardoc_doc.md",
+    input = ":stardoc.bzl",
+    symbol_names = [
+        "stardoc",
+    ],
+    deps = [":stardoc_lib"],
+)
+
+java_binary(
+    name = "stardoc",
+    jvm_flags = [
+        # quiet warnings from com.google.protobuf.UnsafeUtil,
+        # see: https://github.com/google/protobuf/issues/3781
+        # TODO(cparsons): Remove once Stardoc has the fix.
+        "-XX:+IgnoreUnrecognizedVMOptions",
+        "--add-opens=java.base/java.nio=ALL-UNNAMED",
+        "--add-opens=java.base/java.lang=ALL-UNNAMED",
+    ],
+    main_class = "com.google.devtools.build.skydoc.SkydocMain",
+    runtime_deps = [
+        ":prebuilt_stardoc_binary",
+    ],
+)
+
+java_import(
+    name = "prebuilt_stardoc_binary",
+    jars = ["stardoc_binary.jar"],
+    visibility = ["//visibility:private"],
+)
+
+java_binary(
+    name = "renderer",
+    jvm_flags = [
+        # quiet warnings from com.google.protobuf.UnsafeUtil,
+        # see: https://github.com/google/protobuf/issues/3781
+        # TODO(cparsons): Remove once Stardoc has the fix.
+        "-XX:+IgnoreUnrecognizedVMOptions",
+        "--add-opens=java.base/java.nio=ALL-UNNAMED",
+        "--add-opens=java.base/java.lang=ALL-UNNAMED",
+    ],
+    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"],
+)
diff --git a/stardoc/html_tables_stardoc.bzl b/stardoc/html_tables_stardoc.bzl
new file mode 100644
index 0000000..0fef7f8
--- /dev/null
+++ b/stardoc/html_tables_stardoc.bzl
@@ -0,0 +1,37 @@
+# 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.
+
+"""Macro for Pure Markdown Stardoc Output Format"""
+
+load(":stardoc.bzl", "stardoc")
+
+def html_tables_stardoc(name, **kwargs):
+    """Outputs documentation using html_tables templates.
+
+    Args:
+      name: A unique name for this target.
+      **kwargs: Attributes to be passed along to the stardoc() rule. (May not include the attributes
+          for the stardoc and renderer binaries, format, or templates.)
+    """
+
+    stardoc(
+        name = name,
+        format = "markdown",
+        aspect_template = Label("//stardoc:templates/html_tables/aspect.vm"),
+        func_template = Label("//stardoc:templates/html_tables/func.vm"),
+        header_template = Label("//stardoc:templates/html_tables/header.vm"),
+        provider_template = Label("//stardoc:templates/html_tables/provider.vm"),
+        rule_template = Label("//stardoc:templates/html_tables/rule.vm"),
+        **kwargs
+    )
diff --git a/stardoc/renderer_binary.jar b/stardoc/renderer_binary.jar
new file mode 100755
index 0000000..de03de3
--- /dev/null
+++ b/stardoc/renderer_binary.jar
Binary files differ
diff --git a/stardoc/stardoc.bzl b/stardoc/stardoc.bzl
new file mode 100644
index 0000000..456aca7
--- /dev/null
+++ b/stardoc/stardoc.bzl
@@ -0,0 +1,195 @@
+# 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.
+
+"""Starlark rule for stardoc: a documentation generator tool written in Java."""
+
+load("@bazel_skylib//:bzl_library.bzl", "StarlarkLibraryInfo")
+
+def _root_from_file(f):
+    """Given a file, returns the root path of that file."""
+    return f.root.path or "."
+
+def _stardoc_impl(ctx):
+    """Implementation of the stardoc rule."""
+    for semantic_flag in ctx.attr.semantic_flags:
+        if not semantic_flag.startswith("--"):
+            fail("semantic_flags entry '%s' must start with '--'" % semantic_flag)
+    out_file = ctx.outputs.out
+    input_files = depset(direct = [ctx.file.input], transitive = [
+        dep[StarlarkLibraryInfo].transitive_srcs
+        for dep in ctx.attr.deps
+    ])
+    stardoc_args = ctx.actions.args()
+    stardoc_args.add("--input=" + str(ctx.file.input.owner))
+    stardoc_args.add("--workspace_name=" + ctx.label.workspace_name)
+    stardoc_args.add_all(
+        ctx.attr.symbol_names,
+        format_each = "--symbols=%s",
+        omit_if_empty = True,
+    )
+
+    # TODO(cparsons): Note that use of dep_roots alone does not guarantee
+    # the correct file is loaded. If two files exist under the same path
+    # but are under different roots, it is possible that Stardoc loads the
+    # one that is not explicitly an input to this action (if sandboxing is
+    # disabled). The correct way to resolve this is to explicitly specify
+    # the full set of transitive dependency Starlark files as action args
+    # (maybe using a param file), but this requires some work.
+    stardoc_args.add_all(
+        input_files,
+        format_each = "--dep_roots=%s",
+        map_each = _root_from_file,
+        omit_if_empty = True,
+        uniquify = True,
+    )
+    # Needed in case some files are referenced across local repository
+    # namespace. For example, consider a file under a nested local repository @bar
+    # rooted under ./foo/bar/WORKSPACE. Consider a stardoc target 'lib_doc' under
+    # foo/bar/BUILD to document foo/bar/lib.bzl.
+    # The stardoc target references @bar//:lib.bzl (which appears just as :lib.bzl), but the
+    # actual build is taking place in the root repository, thus the source file
+    # is present under external/bar/lib.bzl.
+    stardoc_args.add(
+        "--dep_roots=external/" + ctx.label.workspace_name)
+    stardoc_args.add_all(ctx.attr.semantic_flags)
+    stardoc = ctx.executable.stardoc
+
+    if ctx.attr.format == "proto":
+        stardoc_args.add("--output=" + out_file.path)
+        ctx.actions.run(
+            outputs = [out_file],
+            inputs = input_files,
+            executable = stardoc,
+            arguments = [stardoc_args],
+            mnemonic = "Stardoc",
+            progress_message = ("Generating Starlark doc for %s" %
+                                (ctx.label.name)),
+        )
+    elif ctx.attr.format == "markdown":
+        proto_file = ctx.actions.declare_file(ctx.label.name + ".raw", sibling = out_file)
+        stardoc_args.add("--output=" + proto_file.path)
+        ctx.actions.run(
+            outputs = [proto_file],
+            inputs = input_files,
+            executable = stardoc,
+            arguments = [stardoc_args],
+            mnemonic = "Stardoc",
+            progress_message = ("Generating proto for Starlark doc for %s" %
+                                (ctx.label.name)),
+        )
+        renderer_args = ctx.actions.args()
+        renderer_args.add("--input=" + str(proto_file.path))
+        renderer_args.add("--output=" + str(ctx.outputs.out.path))
+        renderer_args.add("--aspect_template=" + str(ctx.file.aspect_template.path))
+        renderer_args.add("--header_template=" + str(ctx.file.header_template.path))
+        renderer_args.add("--func_template=" + str(ctx.file.func_template.path))
+        renderer_args.add("--provider_template=" + str(ctx.file.provider_template.path))
+        renderer_args.add("--rule_template=" + str(ctx.file.rule_template.path))
+        renderer = ctx.executable.renderer
+        ctx.actions.run(
+            outputs = [out_file],
+            inputs = [proto_file, ctx.file.aspect_template, ctx.file.header_template, ctx.file.func_template, ctx.file.provider_template, ctx.file.rule_template],
+            executable = renderer,
+            arguments = [renderer_args],
+            mnemonic = "Renderer",
+            progress_message = ("Converting proto format of %s to markdown format" %
+                                (ctx.label.name)),
+        )
+
+stardoc = rule(
+    _stardoc_impl,
+    doc = """
+Generates documentation for exported skylark rule definitions in a target starlark file.
+
+This rule is an experimental replacement for the existing skylark_doc rule.
+""",
+    attrs = {
+        "input": attr.label(
+            doc = "The starlark file to generate documentation for.",
+            allow_single_file = [".bzl"],
+        ),
+        "deps": attr.label_list(
+            doc = "A list of skylark_library dependencies which the input depends on.",
+            providers = [StarlarkLibraryInfo],
+        ),
+        "format": attr.string(
+            doc = "The format of the output file. Valid values: 'markdown' or 'proto'.",
+            default = "markdown",
+            values = ["markdown", "proto"],
+        ),
+        "out": attr.output(
+            doc = "The (markdown) file to which documentation will be output.",
+            mandatory = True,
+        ),
+        "symbol_names": attr.string_list(
+            doc = """
+A list of symbol names to generate documentation for. These should correspond to
+the names of rule definitions in the input file. If this list is empty, then
+documentation for all exported rule definitions will be generated.
+""",
+            default = [],
+        ),
+        "semantic_flags": attr.string_list(
+            doc = """
+A list of canonical flags to affect Starlark semantics for the Starlark interpretter
+during documentation generation. This should only be used to maintain compatibility with
+non-default semantic flags required to use the given Starlark symbols.
+
+For example, if `//foo:bar.bzl` does not build except when a user would specify
+`--incompatible_foo_semantic=false`, then this attribute should contain
+"--incompatible_foo_semantic=false".
+""",
+            default = [],
+        ),
+        "stardoc": attr.label(
+            doc = "The location of the stardoc tool.",
+            allow_files = True,
+            default = Label("//stardoc:stardoc"),
+            cfg = "host",
+            executable = True,
+        ),
+        "renderer": attr.label(
+            doc = "The location of the renderer tool.",
+            allow_files = True,
+            default = Label("//stardoc:renderer"),
+            cfg = "host",
+            executable = True,
+        ),
+        "aspect_template": attr.label(
+            doc = "The input file template for generating documentation of aspects.",
+            allow_single_file = [".vm"],
+            default = Label("//stardoc:templates/markdown_tables/aspect.vm"),
+        ),
+        "header_template": attr.label(
+            doc = "The input file template for the header of the output documentation.",
+            allow_single_file = [".vm"],
+            default = Label("//stardoc:templates/markdown_tables/header.vm"),
+        ),
+        "func_template": attr.label(
+            doc = "The input file template for generating documentation of functions.",
+            allow_single_file = [".vm"],
+            default = Label("//stardoc:templates/markdown_tables/func.vm"),
+        ),
+        "provider_template": attr.label(
+            doc = "The input file template for generating documentation of providers.",
+            allow_single_file = [".vm"],
+            default = Label("//stardoc:templates/markdown_tables/provider.vm"),
+        ),
+        "rule_template": attr.label(
+            doc = "The input file template for generating documentation of rules.",
+            allow_single_file = [".vm"],
+            default =Label("//stardoc:templates/markdown_tables/rule.vm"),
+        ),
+    },
+)
diff --git a/stardoc/stardoc_binary.jar b/stardoc/stardoc_binary.jar
new file mode 100755
index 0000000..38d04af
--- /dev/null
+++ b/stardoc/stardoc_binary.jar
Binary files differ
diff --git a/stardoc/templates/html_tables/aspect.vm b/stardoc/templates/html_tables/aspect.vm
new file mode 100644
index 0000000..35e5441
--- /dev/null
+++ b/stardoc/templates/html_tables/aspect.vm
@@ -0,0 +1,56 @@
+<a name="#${aspectName}"></a>
+
+#[[##]]# ${aspectName}
+
+<pre>
+${util.aspectSummary($aspectName, $aspectInfo)}
+</pre>
+
+$aspectInfo.getDocString()
+
+#[[###]]# Aspect Attributes
+
+#if (!$aspectInfo.getAspectAttributeList().isEmpty())
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+#foreach ($aspectAttribute in $aspectInfo.getAspectAttributeList())
+    <tr id="${aspectName}-${aspectAttribute}">
+      <td><code>${aspectAttribute}</code></td>
+      <td>
+        String; required.
+#end
+      </td>
+    </tr>
+#end
+  </tbody>
+</table>
+
+#[[###]]# Attributes
+
+#if (!$aspectInfo.getAttributeList().isEmpty())
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+#foreach ($attribute in $aspectInfo.getAttributeList())
+    <tr id="${aspectName}-${attribute.name}">
+      <td><code>${attribute.name}</code></td>
+      <td>
+        ${util.attributeTypeString($attribute)}; ${util.mandatoryString($attribute)}
+#if (!$attribute.docString.isEmpty())
+        <p>
+          ${attribute.docString.trim()}
+        </p>
+#end
+      </td>
+    </tr>
+#end
+  </tbody>
+</table>
+#end
diff --git a/stardoc/templates/html_tables/func.vm b/stardoc/templates/html_tables/func.vm
new file mode 100644
index 0000000..0f70f7a
--- /dev/null
+++ b/stardoc/templates/html_tables/func.vm
@@ -0,0 +1,36 @@
+<a name="#${funcInfo.functionName}"></a>
+
+#[[##]]# ${funcInfo.functionName}
+
+<pre>
+${util.funcSummary($funcInfo)}
+</pre>
+
+${util.htmlEscape($funcInfo.docString)}
+
+#if (!$funcInfo.getParameterList().isEmpty())
+#[[###]]# Parameters
+
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+#foreach ($param in $funcInfo.getParameterList())
+    <tr id="${funcInfo.functionName}-${param.name}">
+      <td><code>${param.name}</code></td>
+      <td>
+        ${util.mandatoryString($param)}.#if(!$param.getDefaultValue().isEmpty()) default is <code>$param.getDefaultValue()</code>#end
+
+#if (!$param.docString.isEmpty())
+        <p>
+          ${param.docString.trim()}
+        </p>
+#end
+      </td>
+    </tr>
+#end
+  </tbody>
+</table>
+#end
diff --git a/stardoc/templates/html_tables/header.vm b/stardoc/templates/html_tables/header.vm
new file mode 100644
index 0000000..187680d
--- /dev/null
+++ b/stardoc/templates/html_tables/header.vm
@@ -0,0 +1 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
diff --git a/stardoc/templates/html_tables/provider.vm b/stardoc/templates/html_tables/provider.vm
new file mode 100644
index 0000000..1d2f032
--- /dev/null
+++ b/stardoc/templates/html_tables/provider.vm
@@ -0,0 +1,30 @@
+<a name="#${providerName}"></a>
+
+#[[##]]# ${providerName}
+
+<pre>
+${util.providerSummary($providerName, $providerInfo)}
+</pre>
+
+${util.htmlEscape($providerInfo.docString)}
+
+#if (!$providerInfo.fieldInfoList.isEmpty())
+#[[###]]# Fields
+
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+#foreach ($field in $providerInfo.fieldInfoList)
+    <tr id="${providerName}-${field.name}">
+      <td><code>${field.name}</code></td>
+      <td>
+        <p>${field.docString}</p>
+      </td>
+    </tr>
+#end
+  </tbody>
+</table>
+#end
diff --git a/stardoc/templates/html_tables/rule.vm b/stardoc/templates/html_tables/rule.vm
new file mode 100644
index 0000000..71e0999
--- /dev/null
+++ b/stardoc/templates/html_tables/rule.vm
@@ -0,0 +1,40 @@
+<a name="#${ruleName}"></a>
+
+#[[##]]# ${ruleName}
+
+<pre>
+${util.ruleSummary($ruleName, $ruleInfo)}
+</pre>
+
+${util.htmlEscape($ruleInfo.docString)}
+
+#[[###]]# Attributes
+
+#if (!$ruleInfo.getAttributeList().isEmpty())
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+#foreach ($attribute in $ruleInfo.getAttributeList())
+    <tr id="${ruleName}-${attribute.name}">
+      <td><code>${attribute.name}</code></td>
+      <td>
+        ${util.attributeTypeString($attribute)}; ${util.mandatoryString($attribute)}
+#if (!$attribute.docString.isEmpty())
+        <p>
+          ${attribute.docString.trim()}
+        </p>
+#end
+#if (!$attribute.getProviderNameGroupList().isEmpty())
+        <p>
+          The dependencies of this attribute must provide: ${util.attributeProviders($attribute)}
+        </p>
+#end
+      </td>
+    </tr>
+#end
+  </tbody>
+</table>
+#end
diff --git a/stardoc/templates/markdown_tables/aspect.vm b/stardoc/templates/markdown_tables/aspect.vm
new file mode 100644
index 0000000..8bc3391
--- /dev/null
+++ b/stardoc/templates/markdown_tables/aspect.vm
@@ -0,0 +1,32 @@
+<a name="#${aspectName}"></a>
+
+#[[##]]# ${aspectName}
+
+<pre>
+${util.aspectSummary($aspectName, $aspectInfo)}
+</pre>
+
+$aspectInfo.getDocString()
+
+**ASPECT ATTRIBUTES**
+
+#if (!$aspectInfo.getAspectAttributeList().isEmpty())
+
+| Name | Type |
+| :-------------: | :-------------: |
+#foreach ($aspectAttribute in $aspectInfo.getAspectAttributeList())
+| $aspectAttribute| String |
+#end
+#end
+
+
+**ATTRIBUTES**
+
+#if (!$aspectInfo.getAttributeList().isEmpty())
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+#foreach ($attribute in $aspectInfo.getAttributeList())
+| $attribute.name | #if(!$attribute.docString.isEmpty()) ${util.markdownCellFormat($attribute.docString)} #else - #end  | ${util.attributeTypeString($attribute)} | ${util.mandatoryString($attribute)} |  $attribute.defaultValue |
+#end
+#end
diff --git a/stardoc/templates/markdown_tables/func.vm b/stardoc/templates/markdown_tables/func.vm
new file mode 100644
index 0000000..221bb62
--- /dev/null
+++ b/stardoc/templates/markdown_tables/func.vm
@@ -0,0 +1,20 @@
+<a name="#${funcInfo.functionName}"></a>
+
+#[[##]]# ${funcInfo.functionName}
+
+<pre>
+${util.funcSummary($funcInfo)}
+</pre>
+
+${funcInfo.docString}
+
+**PARAMETERS**
+
+#if (!$funcInfo.getParameterList().isEmpty())
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+#foreach ($param in $funcInfo.getParameterList())
+| $param.name | #if(!$param.docString.isEmpty()) ${util.markdownCellFormat($param.docString)} #else <p align="center"> - </p> #end  | #if(!$param.getDefaultValue().isEmpty()) <code>$param.getDefaultValue()</code> #else none #end|
+#end
+#end
diff --git a/stardoc/templates/markdown_tables/header.vm b/stardoc/templates/markdown_tables/header.vm
new file mode 100644
index 0000000..187680d
--- /dev/null
+++ b/stardoc/templates/markdown_tables/header.vm
@@ -0,0 +1 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
diff --git a/stardoc/templates/markdown_tables/provider.vm b/stardoc/templates/markdown_tables/provider.vm
new file mode 100644
index 0000000..4dad9ab
--- /dev/null
+++ b/stardoc/templates/markdown_tables/provider.vm
@@ -0,0 +1,20 @@
+<a name="#${providerName}"></a>
+
+#[[##]]# ${providerName}
+
+<pre>
+${util.providerSummary($providerName, $providerInfo)}
+</pre>
+
+${providerInfo.docString}
+
+**FIELDS**
+
+#if (!$providerInfo.fieldInfoList.isEmpty())
+
+| Name  | Description |
+| :-------------: | :-------------: |
+#foreach ($field in $providerInfo.fieldInfoList)
+| $field.name | #if(!$field.docString.isEmpty()) ${util.markdownCellFormat($field.docString)} #else - #end   |
+#end
+#end
diff --git a/stardoc/templates/markdown_tables/rule.vm b/stardoc/templates/markdown_tables/rule.vm
new file mode 100644
index 0000000..567bc9f
--- /dev/null
+++ b/stardoc/templates/markdown_tables/rule.vm
@@ -0,0 +1,20 @@
+<a name="#${ruleName}"></a>
+
+#[[##]]# ${ruleName}
+
+<pre>
+${util.ruleSummary($ruleName, $ruleInfo)}
+</pre>
+
+${ruleInfo.docString}
+
+**ATTRIBUTES**
+
+#if (!$ruleInfo.getAttributeList().isEmpty())
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+#foreach ($attribute in $ruleInfo.getAttributeList())
+| $attribute.name | #if(!$attribute.docString.isEmpty()) ${util.markdownCellFormat($attribute.docString)} #else - #end  | ${util.attributeTypeString($attribute)} | ${util.mandatoryString($attribute)} | $attribute.defaultValue |
+#end
+#end
diff --git a/test/BUILD b/test/BUILD
new file mode 100644
index 0000000..bc87007
--- /dev/null
+++ b/test/BUILD
@@ -0,0 +1,273 @@
+load(":stardoc_test.bzl", "stardoc_test")
+
+licenses(["notice"])  # Apache 2.0
+
+sh_test(
+    name = "stardoc_self_gen_test",
+    srcs = ["diff_test_runner.sh"],
+    args = [
+        "$(location //stardoc:stardoc_doc.md)",
+        "$(location //:stardoc_rule_doc)",
+    ],
+    data = [
+        "//:stardoc_rule_doc",
+        "//stardoc:stardoc_doc.md",
+    ],
+)
+
+stardoc_test(
+    name = "input_template_test",
+    aspect_template = "testdata/input_template_test/aspect.vm",
+    func_template = "testdata/input_template_test/func.vm",
+    golden_file = "testdata/input_template_test/golden.md",
+    header_template = "testdata/input_template_test/header.vm",
+    input_file = "testdata/input_template_test/input.bzl",
+    provider_template = "testdata/input_template_test/provider.vm",
+    rule_template = "testdata/input_template_test/rule.vm",
+)
+
+stardoc_test(
+    name = "angle_bracket_test",
+    golden_file = "testdata/angle_bracket_test/golden.md",
+    input_file = "testdata/angle_bracket_test/input.bzl",
+)
+
+stardoc_test(
+    name = "proto_format_test",
+    format = "proto",
+    golden_file = "testdata/proto_format_test/golden.raw",
+    input_file = "testdata/proto_format_test/input.bzl",
+)
+
+stardoc_test(
+    name = "cc_api_test",
+    golden_file = "testdata/cc_api_test/golden.md",
+    input_file = "testdata/cc_api_test/input.bzl",
+)
+
+stardoc_test(
+    name = "simple_test",
+    golden_file = "testdata/simple_test/golden.md",
+    input_file = "testdata/simple_test/input.bzl",
+    symbol_names = ["my_rule"],
+)
+
+stardoc_test(
+    name = "repo_rules_test",
+    golden_file = "testdata/repo_rules_test/golden.md",
+    input_file = "testdata/repo_rules_test/input.bzl",
+)
+
+stardoc_test(
+    name = "unknown_name_test",
+    golden_file = "testdata/unknown_name_test/golden.md",
+    input_file = "testdata/unknown_name_test/input.bzl",
+)
+
+stardoc_test(
+    name = "multiple_rules_test",
+    golden_file = "testdata/multiple_rules_test/golden.md",
+    input_file = "testdata/multiple_rules_test/input.bzl",
+)
+
+stardoc_test(
+    name = "android_basic_test",
+    golden_file = "testdata/android_basic_test/golden.md",
+    input_file = "testdata/android_basic_test/input.bzl",
+    semantic_flags = [
+        "--experimental_google_legacy_api",
+    ],
+    symbol_names = ["android_related_rule"],
+)
+
+stardoc_test(
+    name = "apple_basic_test",
+    golden_file = "testdata/apple_basic_test/golden.md",
+    input_file = "testdata/apple_basic_test/input.bzl",
+    symbol_names = ["apple_related_rule"],
+)
+
+stardoc_test(
+    name = "cpp_basic_test",
+    golden_file = "testdata/cpp_basic_test/golden.md",
+    input_file = "testdata/cpp_basic_test/input.bzl",
+    symbol_names = ["cpp_related_rule"],
+)
+
+stardoc_test(
+    name = "java_basic_test",
+    golden_file = "testdata/java_basic_test/golden.md",
+    input_file = "testdata/java_basic_test/input.bzl",
+    symbol_names = ["java_related_rule"],
+)
+
+stardoc_test(
+    name = "multiple_files_test",
+    golden_file = "testdata/multiple_files_test/golden.md",
+    input_file = "testdata/multiple_files_test/input.bzl",
+    deps = [
+        "testdata/multiple_files_test/dep.bzl",
+        "testdata/multiple_files_test/inner_dep.bzl",
+    ],
+)
+
+stardoc_test(
+    name = "same_level_file_test",
+    golden_file = "//test/testdata/same_level_file_test:golden.md",
+    input_file = "//test/testdata/same_level_file_test:input.bzl",
+    symbol_names = ["my_rule"],
+    deps = [
+        "//test/testdata/same_level_file_test:dep.bzl",
+    ],
+)
+
+stardoc_test(
+    name = "misc_apis_test",
+    golden_file = "testdata/misc_apis_test/golden.md",
+    input_file = "testdata/misc_apis_test/input.bzl",
+)
+
+stardoc_test(
+    name = "attribute_types_test",
+    golden_file = "testdata/attribute_types_test/golden.md",
+    input_file = "testdata/attribute_types_test/input.bzl",
+    symbol_names = ["my_rule"],
+)
+
+stardoc_test(
+    name = "filter_rules_test",
+    golden_file = "testdata/filter_rules_test/golden.md",
+    input_file = "testdata/filter_rules_test/input.bzl",
+    symbol_names = [
+        "my_rule",
+        "whitelisted_dep_rule",
+    ],
+    deps = [
+        "testdata/filter_rules_test/dep.bzl",
+    ],
+)
+
+stardoc_test(
+    name = "provider_basic_test",
+    golden_file = "testdata/provider_basic_test/golden.md",
+    input_file = "testdata/provider_basic_test/input.bzl",
+)
+
+stardoc_test(
+    name = "function_basic_test",
+    golden_file = "testdata/function_basic_test/golden.md",
+    input_file = "testdata/function_basic_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",
+    golden_file = "testdata/namespace_test/golden.md",
+    input_file = "testdata/namespace_test/input.bzl",
+    symbol_names = [
+        "my_namespace",
+    ],
+)
+
+stardoc_test(
+    name = "multi_level_namespace_test",
+    golden_file = "testdata/multi_level_namespace_test/golden.md",
+    input_file = "testdata/multi_level_namespace_test/input.bzl",
+)
+
+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",
+    symbol_names = [
+        "my_namespace",
+        "other_namespace.foo.nothing",
+    ],
+)
+
+stardoc_test(
+    name = "macro_kwargs_test",
+    golden_file = "testdata/macro_kwargs_test/golden.md",
+    input_file = "testdata/macro_kwargs_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",
+    symbol_names = ["py_related_rule"],
+)
+
+stardoc_test(
+    name = "struct_default_value_test",
+    golden_file = "testdata/struct_default_value_test/golden.md",
+    input_file = "testdata/struct_default_value_test/input.bzl",
+)
+
+stardoc_test(
+    name = "aspect_test",
+    golden_file = "testdata/aspect_test/golden.md",
+    input_file = "testdata/aspect_test/input.bzl",
+)
+
+stardoc_test(
+    name = "providers_for_attributes_test",
+    golden_file = "testdata/providers_for_attributes_test/golden.md",
+    input_file = "testdata/providers_for_attributes_test/input.bzl",
+    deps = [
+        "testdata/providers_for_attributes_test/dep.bzl",
+    ],
+)
+
+stardoc_test(
+    name = "html_tables_template_test",
+    golden_file = "testdata/html_tables_template_test/golden.md",
+    input_file = "testdata/html_tables_template_test/input.bzl",
+    test = "html_tables",
+)
+
+stardoc_test(
+    name = "attribute_defaults_test",
+    golden_file = "testdata/attribute_defaults_test/golden.md",
+    input_file = "testdata/attribute_defaults_test/input.bzl",
+)
+
+stardoc_test(
+    name = "config_apis_test",
+    golden_file = "testdata/config_apis_test/golden.md",
+    input_file = "testdata/config_apis_test/input.bzl",
+)
+
+genrule(
+    name = "generate_bzl_test_dep",
+    srcs = ["testdata/generated_bzl_test/dep.bzl.tpl"],
+    outs = ["testdata/generated_bzl_test/dep.bzl"],
+    cmd = "cp $< $@",
+)
+
+stardoc_test(
+    name = "generated_bzl_test",
+    golden_file = "testdata/generated_bzl_test/golden.md",
+    input_file = "testdata/generated_bzl_test/input.bzl",
+    deps = [
+        "testdata/generated_bzl_test/dep.bzl",
+    ],
+)
+
+sh_test(
+    name = "local_repository_test_e2e_test",
+    srcs = ["diff_test_runner.sh"],
+    args = [
+        "$(location @local_repository_test//:output.md)",
+        "$(location @local_repository_test//:golden.md)",
+    ],
+    data = [
+        "@local_repository_test//:golden.md",
+        "@local_repository_test//:output.md",
+    ],
+)
diff --git a/test/diff_test_runner.sh b/test/diff_test_runner.sh
new file mode 100755
index 0000000..0f4fa47
--- /dev/null
+++ b/test/diff_test_runner.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# 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.
+#
+# A shell test that the contents of an input file match a golden file.
+#
+# Usage: diff_test_runner.sh ACTUAL_FILE GOLDEN_FILE
+
+set -u
+
+actual_file=$1
+shift 1
+golden_file=$1
+shift 1
+
+DIFF="$(diff ${actual_file} ${golden_file})"
+
+if [ "$DIFF" != "" ]
+then
+    echo "FAIL: Actual did not match golden."
+    echo "${DIFF}"
+    exit 1
+else
+    echo "SUCCESS: Result matches golden file"
+fi
diff --git a/test/stardoc_test.bzl b/test/stardoc_test.bzl
new file mode 100644
index 0000000..4db9c50
--- /dev/null
+++ b/test/stardoc_test.bzl
@@ -0,0 +1,121 @@
+# 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.
+"""Convenience macro for stardoc e2e tests."""
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load("//stardoc:html_tables_stardoc.bzl", "html_tables_stardoc")
+load("//stardoc:stardoc.bzl", "stardoc")
+
+def stardoc_test(
+        name,
+        input_file,
+        golden_file,
+        deps = [],
+        test = "default",
+        **kwargs):
+    """Convenience macro for stardoc e2e test suites.
+
+    Each invocation creates four targets:
+
+    1. A sh_test target which verifies that stardoc-built-from-source, when run on an input file,
+       creates output matching the contents of a golden file, named "{name}_e2e_test".
+    2. A `stardoc` target which will generate a new golden file given an input file
+       with stardoc-built-from-source. This target should be used to regenerate
+       the golden file when updating stardoc, named "regenerate_{name}_golden".
+    3 & 4. Targets identical to (1) and (2) except they use the prebuilt-stardoc jar, and
+       are named "{name}_e2e_jar_test" and "regenerate_with_jar_{name}_golden".
+    5. A bzl_library target for convenient wrapping of input bzl files, named "{name}_lib".
+
+    Args:
+      name: A unique name to qualify the created targets.
+      input_file: The label string of the Starlark input file for which documentation is generated
+          in this test.
+      golden_file: The label string of the golden file containing the documentation when stardoc
+          is run on the input file.
+      deps: A list of label strings of starlark file dependencies of the input_file.
+      test: The type of test (default or html_tables).
+      **kwargs: A dictionary of input template names mapped to template file path for which documentation is generated.
+      """
+
+    bzl_library(
+        name = "%s_lib" % name,
+        srcs = [input_file],
+        deps = deps,
+    )
+    _create_test_targets(test_name = "%s_e2e_test" % name,
+        genrule_name = "regenerate_%s_golden" % name,
+        lib_name = "%s_lib" % name,
+        input_file = input_file,
+        golden_file = golden_file,
+        stardoc_bin = "@io_bazel//src/main/java/com/google/devtools/build/skydoc",
+        renderer_bin = "@io_bazel//src/main/java/com/google/devtools/build/skydoc/renderer",
+        test = test,
+        **kwargs)
+    _create_test_targets(test_name = "%s_e2e_jar_test" % name,
+        genrule_name = "regenerate_with_jar_%s_golden" % name,
+        lib_name = "%s_lib" % name,
+        input_file = input_file,
+        golden_file = golden_file,
+        stardoc_bin = "@io_bazel//src/main/java/com/google/devtools/build/skydoc",
+        renderer_bin = "@io_bazel//src/main/java/com/google/devtools/build/skydoc/renderer",
+        test = test,
+        **kwargs)
+
+def _create_test_targets(test_name,
+                         genrule_name,
+                         lib_name,
+                         input_file,
+                         golden_file,
+                         stardoc_bin,
+                         renderer_bin,
+                         test,
+                         **kwargs):
+    actual_generated_doc = "%s.out" % genrule_name
+
+    native.sh_test(
+        name = test_name,
+        srcs = ["diff_test_runner.sh"],
+        args = [
+            "$(location %s)" % actual_generated_doc,
+            "$(location %s)" % golden_file,
+        ],
+        data = [
+            actual_generated_doc,
+            golden_file,
+        ],
+    )
+
+    if test == "default":
+        stardoc(
+            name = genrule_name,
+            out = actual_generated_doc,
+            input = input_file,
+            deps = [lib_name],
+            renderer = renderer_bin,
+            stardoc = stardoc_bin,
+            **kwargs
+        )
+    elif test == "html_tables":
+        html_tables_stardoc(
+            name = genrule_name,
+            out = actual_generated_doc,
+            input = input_file,
+            deps = [lib_name],
+            renderer = renderer_bin,
+            stardoc = stardoc_bin,
+            **kwargs
+        )
+    else:
+        fail("parameter 'test' must either be 'default' or 'html_tables', but was " + test)
+
diff --git a/test/testdata/android_basic_test/golden.md b/test/testdata/android_basic_test/golden.md
new file mode 100755
index 0000000..5c61869
--- /dev/null
+++ b/test/testdata/android_basic_test/golden.md
@@ -0,0 +1,24 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#android_related_rule"></a>
+
+## android_related_rule
+
+<pre>
+android_related_rule(<a href="#android_related_rule-name">name</a>, <a href="#android_related_rule-first">first</a>, <a href="#android_related_rule-fourth">fourth</a>, <a href="#android_related_rule-second">second</a>, <a href="#android_related_rule-third">third</a>)
+</pre>
+
+This rule does android-related things.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| fourth |  -   | Boolean | optional | False |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| third |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
diff --git a/test/testdata/android_basic_test/input.bzl b/test/testdata/android_basic_test/input.bzl
new file mode 100644
index 0000000..11feec1
--- /dev/null
+++ b/test/testdata/android_basic_test/input.bzl
@@ -0,0 +1,27 @@
+# buildifier: disable=module-docstring
+# buildifier: disable=function-docstring
+def exercise_the_api():
+    _var1 = android_common.create_device_broker_info("")
+    _var2 = ApkInfo
+    _var3 = AndroidInstrumentationInfo
+    _var4 = AndroidDeviceBrokerInfo
+    _var5 = AndroidResourcesInfo
+    _var6 = AndroidNativeLibsInfo
+    _var7 = AndroidSdkInfo
+    _var8 = android_data
+
+exercise_the_api()
+
+def my_rule_impl(ctx):
+    return []
+
+android_related_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This rule does android-related things.",
+    attrs = {
+        "first": attr.label(mandatory = True, allow_single_file = True),
+        "second": attr.string_dict(mandatory = True),
+        "third": attr.output(mandatory = True),
+        "fourth": attr.bool(default = False, mandatory = False),
+    },
+)
diff --git a/test/testdata/angle_bracket_test/golden.md b/test/testdata/angle_bracket_test/golden.md
new file mode 100755
index 0000000..c86d62b
--- /dev/null
+++ b/test/testdata/angle_bracket_test/golden.md
@@ -0,0 +1,62 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_anglebrac"></a>
+
+## my_anglebrac
+
+<pre>
+my_anglebrac(<a href="#my_anglebrac-name">name</a>, <a href="#my_anglebrac-useless">useless</a>)
+</pre>
+
+Rule with <brackets>
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| useless |  Args with some tags: &lt;tag1&gt;, &lt;tag2&gt;   | String | optional | "Find <brackets>" |
+
+
+<a name="#bracketuse"></a>
+
+## bracketuse
+
+<pre>
+bracketuse(<a href="#bracketuse-foo">foo</a>, <a href="#bracketuse-bar">bar</a>, <a href="#bracketuse-baz">baz</a>)
+</pre>
+
+Information with <brackets>
+
+**FIELDS**
+
+
+| Name  | Description |
+| :-------------: | :-------------: |
+| foo |  A string representing &lt;foo&gt;    |
+| bar |  A string representing bar    |
+| baz |  A string representing baz    |
+
+
+<a name="#bracket_function"></a>
+
+## bracket_function
+
+<pre>
+bracket_function(<a href="#bracket_function-name">name</a>)
+</pre>
+
+Dummy docstring with <brackets>.
+
+This rule runs checks on <angle brackets>.
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| name |  an arg with **formatted** docstring.   |  none |
+
+
diff --git a/test/testdata/angle_bracket_test/input.bzl b/test/testdata/angle_bracket_test/input.bzl
new file mode 100644
index 0000000..0f3a45c
--- /dev/null
+++ b/test/testdata/angle_bracket_test/input.bzl
@@ -0,0 +1,38 @@
+"""Input file to test angle bracket bug (https://github.com/bazelbuild/skydoc/issues/186)"""
+
+def bracket_function(name):
+    """Dummy docstring with <brackets>.
+
+    This rule runs checks on <angle brackets>.
+
+    Args:
+        name: an arg with **formatted** docstring.
+
+    Returns:
+        some <angled> brackets
+
+    """
+    pass
+
+bracketuse = provider(
+    doc = "Information with <brackets>",
+    fields = {
+        "foo": "A string representing <foo>",
+        "bar": "A string representing bar",
+        "baz": "A string representing baz",
+    },
+)
+
+def _rule_impl(ctx):
+    return []
+
+my_anglebrac = rule(
+    implementation = _rule_impl,
+    doc = "Rule with <brackets>",
+    attrs = {
+        "useless": attr.string(
+            doc = "Args with some tags: <tag1>, <tag2>",
+            default = "Find <brackets>",
+        ),
+    },
+)
diff --git a/test/testdata/apple_basic_test/golden.md b/test/testdata/apple_basic_test/golden.md
new file mode 100755
index 0000000..a793122
--- /dev/null
+++ b/test/testdata/apple_basic_test/golden.md
@@ -0,0 +1,24 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#apple_related_rule"></a>
+
+## apple_related_rule
+
+<pre>
+apple_related_rule(<a href="#apple_related_rule-name">name</a>, <a href="#apple_related_rule-first">first</a>, <a href="#apple_related_rule-fourth">fourth</a>, <a href="#apple_related_rule-second">second</a>, <a href="#apple_related_rule-third">third</a>)
+</pre>
+
+This rule does apple-related things.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| fourth |  -   | Boolean | optional | False |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| third |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
diff --git a/test/testdata/apple_basic_test/input.bzl b/test/testdata/apple_basic_test/input.bzl
new file mode 100644
index 0000000..c5801ba
--- /dev/null
+++ b/test/testdata/apple_basic_test/input.bzl
@@ -0,0 +1,22 @@
+# buildifier: disable=module-docstring
+# buildifier: disable=function-docstring
+def exercise_the_api():
+    var1 = apple_common.platform_type
+    var2 = apple_common.AppleDynamicFramework
+
+exercise_the_api()
+
+# buildifier: disable=rule-impl-return
+def my_rule_impl(ctx):
+    return struct()
+
+apple_related_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This rule does apple-related things.",
+    attrs = {
+        "first": attr.label(mandatory = True, allow_single_file = True),
+        "second": attr.string_dict(mandatory = True),
+        "third": attr.output(mandatory = True),
+        "fourth": attr.bool(default = False, mandatory = False),
+    },
+)
diff --git a/test/testdata/aspect_test/golden.md b/test/testdata/aspect_test/golden.md
new file mode 100755
index 0000000..065e134
--- /dev/null
+++ b/test/testdata/aspect_test/golden.md
@@ -0,0 +1,76 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_aspect_impl"></a>
+
+## my_aspect_impl
+
+<pre>
+my_aspect_impl(<a href="#my_aspect_impl-ctx">ctx</a>)
+</pre>
+
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| ctx |  <p align="center"> - </p>   |  none |
+
+
+<a name="#my_aspect"></a>
+
+## my_aspect
+
+<pre>
+my_aspect(<a href="#my_aspect-name">name</a>, <a href="#my_aspect-first">first</a>, <a href="#my_aspect-second">second</a>)
+</pre>
+
+This is my aspect. It does stuff.
+
+**ASPECT ATTRIBUTES**
+
+
+| Name | Type |
+| :-------------: | :-------------: |
+| deps| String |
+| attr_aspect| String |
+
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |   |
+| first |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |   |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |   |
+
+
+<a name="#other_aspect"></a>
+
+## other_aspect
+
+<pre>
+other_aspect(<a href="#other_aspect-name">name</a>, <a href="#other_aspect-third">third</a>)
+</pre>
+
+This is another aspect.
+
+**ASPECT ATTRIBUTES**
+
+
+| Name | Type |
+| :-------------: | :-------------: |
+| *| String |
+
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |   |
+| third |  -   | Integer | required |   |
+
+
diff --git a/test/testdata/aspect_test/input.bzl b/test/testdata/aspect_test/input.bzl
new file mode 100644
index 0000000..1ffedb4
--- /dev/null
+++ b/test/testdata/aspect_test/input.bzl
@@ -0,0 +1,24 @@
+"""The input file for the aspect test"""
+
+def my_aspect_impl(ctx):
+    return []
+
+my_aspect = aspect(
+    implementation = my_aspect_impl,
+    doc = "This is my aspect. It does stuff.",
+    attr_aspects = ["deps", "attr_aspect"],
+    attrs = {
+        "first": attr.label(mandatory = True, allow_single_file = True),
+        "second": attr.string_dict(mandatory = True),
+    },
+)
+
+other_aspect = aspect(
+    implementation = my_aspect_impl,
+    doc = "This is another aspect.",
+    attr_aspects = ["*"],
+    attrs = {
+        "_hidden": attr.string(),
+        "third": attr.int(mandatory = True),
+    },
+)
diff --git a/test/testdata/attribute_defaults_test/golden.md b/test/testdata/attribute_defaults_test/golden.md
new file mode 100755
index 0000000..2dce74d
--- /dev/null
+++ b/test/testdata/attribute_defaults_test/golden.md
@@ -0,0 +1,72 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-a">a</a>, <a href="#my_rule-b">b</a>, <a href="#my_rule-c">c</a>, <a href="#my_rule-d">d</a>, <a href="#my_rule-e">e</a>, <a href="#my_rule-f">f</a>, <a href="#my_rule-g">g</a>, <a href="#my_rule-h">h</a>, <a href="#my_rule-i">i</a>, <a href="#my_rule-j">j</a>, <a href="#my_rule-k">k</a>, <a href="#my_rule-l">l</a>, <a href="#my_rule-m">m</a>, <a href="#my_rule-n">n</a>, <a href="#my_rule-o">o</a>, <a href="#my_rule-p">p</a>, <a href="#my_rule-q">q</a>, <a href="#my_rule-r">r</a>, <a href="#my_rule-s">s</a>, <a href="#my_rule-t">t</a>, <a href="#my_rule-u">u</a>, <a href="#my_rule-v">v</a>, <a href="#my_rule-w">w</a>)
+</pre>
+
+This is my rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| a |  Some bool   | Boolean | optional | False |
+| b |  Some int   | Integer | optional | 2 |
+| c |  Some int_list   | List of integers | optional | [0, 1] |
+| d |  Some label   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | //foo:bar |
+| e |  Some label_keyed_string_dict   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: Label -> String</a> | optional | {"//foo:bar": "hello", "//bar:baz": "goodbye"} |
+| f |  Some label_list   | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | ["//foo:bar", "//bar:baz"] |
+| g |  Some string   | String | optional | "" |
+| h |  Some string_dict   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {"animal": "bunny", "color": "orange"} |
+| i |  Some string_list   | List of strings | optional | ["cat", "dog"] |
+| j |  Some string_list_dict   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> List of strings</a> | optional | {"animal": ["cat", "bunny"], "color": ["blue", "orange"]} |
+| k |  Some bool   | Boolean | required |  |
+| l |  Some int   | Integer | required |  |
+| m |  Some int_list   | List of integers | required |  |
+| n |  Some label   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| o |  Some label_keyed_string_dict   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: Label -> String</a> | required |  |
+| p |  Some label_list   | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | required |  |
+| q |  Some string   | String | required |  |
+| r |  Some string_dict   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| s |  Some string_list   | List of strings | required |  |
+| t |  Some string_list_dict   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> List of strings</a> | required |  |
+| u |  -   | String | optional | "" |
+| v |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
+| w |  -   | Integer | optional | 0 |
+
+
+<a name="#my_aspect"></a>
+
+## my_aspect
+
+<pre>
+my_aspect(<a href="#my_aspect-name">name</a>, <a href="#my_aspect-y">y</a>, <a href="#my_aspect-z">z</a>)
+</pre>
+
+This is my aspect. It does stuff.
+
+**ASPECT ATTRIBUTES**
+
+
+| Name | Type |
+| :-------------: | :-------------: |
+| deps| String |
+| attr_aspect| String |
+
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |   |
+| y |  some string   | String | optional |  "why" |
+| z |  -   | String | required |   |
+
+
diff --git a/test/testdata/attribute_defaults_test/input.bzl b/test/testdata/attribute_defaults_test/input.bzl
new file mode 100644
index 0000000..fe891f6
--- /dev/null
+++ b/test/testdata/attribute_defaults_test/input.bzl
@@ -0,0 +1,57 @@
+"""A golden test to verify attribute default values."""
+
+def _my_rule_impl(ctx):
+    return []
+
+def _my_aspect_impl(target, ctx):
+    return []
+
+my_aspect = aspect(
+    implementation = _my_aspect_impl,
+    doc = "This is my aspect. It does stuff.",
+    attr_aspects = ["deps", "attr_aspect"],
+    attrs = {
+        "_x": attr.label(mandatory = True),
+        "y": attr.string(default = "why", doc = "some string"),
+        "z": attr.string(mandatory = True),
+    },
+)
+
+my_rule = rule(
+    implementation = _my_rule_impl,
+    doc = "This is my rule. It does stuff.",
+    attrs = {
+        "a": attr.bool(default = False, doc = "Some bool"),
+        "b": attr.int(default = 2, doc = "Some int"),
+        "c": attr.int_list(default = [0, 1], doc = "Some int_list"),
+        "d": attr.label(default = "//foo:bar", doc = "Some label"),
+        "e": attr.label_keyed_string_dict(
+            default = {"//foo:bar": "hello", "//bar:baz": "goodbye"},
+            doc = "Some label_keyed_string_dict",
+        ),
+        "f": attr.label_list(default = ["//foo:bar", "//bar:baz"], doc = "Some label_list"),
+        "g": attr.string(default = "", doc = "Some string"),
+        "h": attr.string_dict(
+            default = {"animal": "bunny", "color": "orange"},
+            doc = "Some string_dict",
+        ),
+        "i": attr.string_list(default = ["cat", "dog"], doc = "Some string_list"),
+        "j": attr.string_list_dict(
+            default = {"animal": ["cat", "bunny"], "color": ["blue", "orange"]},
+            doc = "Some string_list_dict",
+        ),
+        "k": attr.bool(mandatory = True, doc = "Some bool"),
+        "l": attr.int(mandatory = True, doc = "Some int"),
+        "m": attr.int_list(mandatory = True, doc = "Some int_list"),
+        "n": attr.label(mandatory = True, doc = "Some label"),
+        "o": attr.label_keyed_string_dict(mandatory = True, doc = "Some label_keyed_string_dict"),
+        "p": attr.label_list(mandatory = True, doc = "Some label_list"),
+        "q": attr.string(mandatory = True, doc = "Some string"),
+        "r": attr.string_dict(mandatory = True, doc = "Some string_dict"),
+        "s": attr.string_list(mandatory = True, doc = "Some string_list"),
+        "t": attr.string_list_dict(mandatory = True, doc = "Some string_list_dict"),
+        "u": attr.string(),
+        "v": attr.label(),
+        "w": attr.int()
+    },
+)
diff --git a/test/testdata/attribute_types_test/golden.md b/test/testdata/attribute_types_test/golden.md
new file mode 100755
index 0000000..c55d06f
--- /dev/null
+++ b/test/testdata/attribute_types_test/golden.md
@@ -0,0 +1,32 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-a">a</a>, <a href="#my_rule-b">b</a>, <a href="#my_rule-c">c</a>, <a href="#my_rule-d">d</a>, <a href="#my_rule-e">e</a>, <a href="#my_rule-f">f</a>, <a href="#my_rule-g">g</a>, <a href="#my_rule-h">h</a>, <a href="#my_rule-i">i</a>, <a href="#my_rule-j">j</a>, <a href="#my_rule-k">k</a>, <a href="#my_rule-l">l</a>)
+</pre>
+
+This is my rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| a |  Some bool   | Boolean | required |  |
+| b |  Some int   | Integer | required |  |
+| c |  Some int_list   | List of integers | required |  |
+| d |  Some label   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| e |  Some label_keyed_string_dict   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: Label -> String</a> | required |  |
+| f |  Some label_list   | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | required |  |
+| g |  Some output   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
+| h |  Some output_list   | List of labels | optional | None |
+| i |  Some string   | String | required |  |
+| j |  Some string_dict   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| k |  Some string_list   | List of strings | required |  |
+| l |  Some string_list_dict   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> List of strings</a> | optional | {} |
+
+
diff --git a/test/testdata/attribute_types_test/input.bzl b/test/testdata/attribute_types_test/input.bzl
new file mode 100644
index 0000000..adbe695
--- /dev/null
+++ b/test/testdata/attribute_types_test/input.bzl
@@ -0,0 +1,23 @@
+# buildifier: disable=module-docstring
+# buildifier: disable=function-docstring
+def my_rule_impl(ctx):
+    return []
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is my rule. It does stuff.",
+    attrs = {
+        "a": attr.bool(mandatory = True, doc = "Some bool"),
+        "b": attr.int(mandatory = True, doc = "Some int"),
+        "c": attr.int_list(mandatory = True, doc = "Some int_list"),
+        "d": attr.label(mandatory = True, doc = "Some label"),
+        "e": attr.label_keyed_string_dict(mandatory = True, doc = "Some label_keyed_string_dict"),
+        "f": attr.label_list(mandatory = True, doc = "Some label_list"),
+        "g": attr.output(mandatory = False, doc = "Some output"),
+        "h": attr.output_list(mandatory = False, doc = "Some output_list"),
+        "i": attr.string(mandatory = True, doc = "Some string"),
+        "j": attr.string_dict(mandatory = True, doc = "Some string_dict"),
+        "k": attr.string_list(mandatory = True, doc = "Some string_list"),
+        "l": attr.string_list_dict(mandatory = False, doc = "Some string_list_dict"),
+    },
+)
diff --git a/test/testdata/cc_api_test/golden.md b/test/testdata/cc_api_test/golden.md
new file mode 100755
index 0000000..79ae8b5
--- /dev/null
+++ b/test/testdata/cc_api_test/golden.md
@@ -0,0 +1,56 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#cpp_related_rule"></a>
+
+## cpp_related_rule
+
+<pre>
+cpp_related_rule(<a href="#cpp_related_rule-name">name</a>, <a href="#cpp_related_rule-first">first</a>, <a href="#cpp_related_rule-fourth">fourth</a>, <a href="#cpp_related_rule-second">second</a>, <a href="#cpp_related_rule-third">third</a>)
+</pre>
+
+This rule does C++-related things.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| fourth |  -   | Boolean | optional | False |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| third |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
+<a name="#exercise_the_api"></a>
+
+## exercise_the_api
+
+<pre>
+exercise_the_api()
+</pre>
+
+
+
+**PARAMETERS**
+
+
+
+<a name="#my_rule_impl"></a>
+
+## my_rule_impl
+
+<pre>
+my_rule_impl(<a href="#my_rule_impl-ctx">ctx</a>)
+</pre>
+
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| ctx |  <p align="center"> - </p>   |  none |
+
+
diff --git a/test/testdata/cc_api_test/input.bzl b/test/testdata/cc_api_test/input.bzl
new file mode 100644
index 0000000..17462fd
--- /dev/null
+++ b/test/testdata/cc_api_test/input.bzl
@@ -0,0 +1,20 @@
+"""Input file for C++ api test """
+
+def exercise_the_api():
+    var1 = CcInfo
+
+exercise_the_api()
+
+def my_rule_impl(ctx):
+    return []
+
+cpp_related_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This rule does C++-related things.",
+    attrs = {
+        "first": attr.label(mandatory = True, allow_single_file = True),
+        "second": attr.string_dict(mandatory = True),
+        "third": attr.output(mandatory = True),
+        "fourth": attr.bool(default = False, mandatory = False),
+    },
+)
diff --git a/test/testdata/config_apis_test/golden.md b/test/testdata/config_apis_test/golden.md
new file mode 100755
index 0000000..7cdab56
--- /dev/null
+++ b/test/testdata/config_apis_test/golden.md
@@ -0,0 +1,70 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#int_setting"></a>
+
+## int_setting
+
+<pre>
+int_setting(<a href="#int_setting-name">name</a>)
+</pre>
+
+
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+
+
+<a name="#string_flag"></a>
+
+## string_flag
+
+<pre>
+string_flag(<a href="#string_flag-name">name</a>)
+</pre>
+
+
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+
+
+<a name="#exercise_the_api"></a>
+
+## exercise_the_api
+
+<pre>
+exercise_the_api()
+</pre>
+
+
+
+**PARAMETERS**
+
+
+
+<a name="#transition_func"></a>
+
+## transition_func
+
+<pre>
+transition_func(<a href="#transition_func-settings">settings</a>)
+</pre>
+
+A no-op transition function.
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| settings |  <p align="center"> - </p>   |  none |
+
+
diff --git a/test/testdata/config_apis_test/input.bzl b/test/testdata/config_apis_test/input.bzl
new file mode 100644
index 0000000..5519711
--- /dev/null
+++ b/test/testdata/config_apis_test/input.bzl
@@ -0,0 +1,25 @@
+# buildifier: disable=module-docstring
+# buildifier: disable=function-docstring
+def exercise_the_api():
+    _var6 = configuration_field("foo", "bar")
+
+exercise_the_api()
+
+def transition_func(settings):
+    """A no-op transition function."""
+    return settings
+
+my_transition = transition(implementation = transition_func, inputs = [], outputs = [])
+
+def _build_setting_impl(ctx):
+    return []
+
+string_flag = rule(
+    implementation = _build_setting_impl,
+    build_setting = config.string(flag = True),
+)
+
+int_setting = rule(
+    implementation = _build_setting_impl,
+    build_setting = config.int(flag = False),
+)
diff --git a/test/testdata/cpp_basic_test/golden.md b/test/testdata/cpp_basic_test/golden.md
new file mode 100755
index 0000000..21d4723
--- /dev/null
+++ b/test/testdata/cpp_basic_test/golden.md
@@ -0,0 +1,24 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#cpp_related_rule"></a>
+
+## cpp_related_rule
+
+<pre>
+cpp_related_rule(<a href="#cpp_related_rule-name">name</a>, <a href="#cpp_related_rule-first">first</a>, <a href="#cpp_related_rule-fourth">fourth</a>, <a href="#cpp_related_rule-second">second</a>, <a href="#cpp_related_rule-third">third</a>)
+</pre>
+
+This rule does cpp-related things.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| fourth |  -   | Boolean | optional | False |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| third |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
diff --git a/test/testdata/cpp_basic_test/input.bzl b/test/testdata/cpp_basic_test/input.bzl
new file mode 100644
index 0000000..b927e42
--- /dev/null
+++ b/test/testdata/cpp_basic_test/input.bzl
@@ -0,0 +1,20 @@
+# buildifier: disable=module-docstring
+# buildifier: disable=function-docstring
+def exercise_the_api():
+    var1 = cc_common.CcToolchainInfo
+
+exercise_the_api()
+
+def my_rule_impl(ctx):
+    return []
+
+cpp_related_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This rule does cpp-related things.",
+    attrs = {
+        "first": attr.label(mandatory = True, allow_single_file = True),
+        "second": attr.string_dict(mandatory = True),
+        "third": attr.output(mandatory = True),
+        "fourth": attr.bool(default = False, mandatory = False),
+    },
+)
diff --git a/test/testdata/filter_rules_test/dep.bzl b/test/testdata/filter_rules_test/dep.bzl
new file mode 100644
index 0000000..5c5da10
--- /dev/null
+++ b/test/testdata/filter_rules_test/dep.bzl
@@ -0,0 +1,16 @@
+# buildifier: disable=module-docstring
+def my_rule_impl(ctx):
+  return []
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is the dep rule. It does stuff.",
+    attrs = {
+        "first": attr.label(
+            mandatory = True,
+            doc = "dep's my_rule doc string",
+            allow_single_file = True,
+        ),
+        "second": attr.string_dict(mandatory = True),
+    },
+)
diff --git a/test/testdata/filter_rules_test/golden.md b/test/testdata/filter_rules_test/golden.md
new file mode 100755
index 0000000..12e985f
--- /dev/null
+++ b/test/testdata/filter_rules_test/golden.md
@@ -0,0 +1,42 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-first">first</a>, <a href="#my_rule-second">second</a>)
+</pre>
+
+This is my rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  first my_rule doc string   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+
+
+<a name="#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 |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  dep's my_rule doc string   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+
+
diff --git a/test/testdata/filter_rules_test/input.bzl b/test/testdata/filter_rules_test/input.bzl
new file mode 100644
index 0000000..5b8679c
--- /dev/null
+++ b/test/testdata/filter_rules_test/input.bzl
@@ -0,0 +1,40 @@
+# buildifier: disable=module-docstring
+load(
+    ":testdata/filter_rules_test/dep.bzl",
+    "my_rule_impl",
+    dep_rule = "my_rule",
+)
+
+def my_rule_impl(ctx):
+    return []
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is my rule. It does stuff.",
+    attrs = {
+        "first": attr.label(
+            mandatory = True,
+            doc = "first my_rule doc string",
+            allow_single_file = True,
+        ),
+        "second": attr.string_dict(mandatory = True),
+    },
+)
+
+other_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is another rule.",
+    attrs = {
+        "test": attr.string_dict(mandatory = True),
+    },
+)
+
+whitelisted_dep_rule = dep_rule
+
+yet_another_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is yet another rule",
+    attrs = {
+        "test": attr.string_dict(mandatory = True),
+    },
+)
diff --git a/test/testdata/function_basic_test/golden.md b/test/testdata/function_basic_test/golden.md
new file mode 100755
index 0000000..0fca193
--- /dev/null
+++ b/test/testdata/function_basic_test/golden.md
@@ -0,0 +1,52 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#check_sources"></a>
+
+## check_sources
+
+<pre>
+check_sources(<a href="#check_sources-name">name</a>, <a href="#check_sources-required_param">required_param</a>, <a href="#check_sources-bool_param">bool_param</a>, <a href="#check_sources-srcs">srcs</a>, <a href="#check_sources-string_param">string_param</a>, <a href="#check_sources-int_param">int_param</a>, <a href="#check_sources-dict_param">dict_param</a>,
+              <a href="#check_sources-struct_param">struct_param</a>)
+</pre>
+
+Runs some checks on the given source files.
+
+This rule runs checks on a given set of source files.
+Use `bazel build` to run the check.
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this rule.   |  none |
+| required_param |  Use your imagination.   |  none |
+| bool_param |  <p align="center"> - </p>   |  <code>True</code> |
+| srcs |  Source files to run the checks against.   |  <code>[]</code> |
+| string_param |  <p align="center"> - </p>   |  <code>""</code> |
+| int_param |  Your favorite number.   |  <code>2</code> |
+| dict_param |  <p align="center"> - </p>   |  <code>{}</code> |
+| struct_param |  <p align="center"> - </p>   |  <code>struct(foo = "bar")</code> |
+
+
+<a name="#undocumented_function"></a>
+
+## undocumented_function
+
+<pre>
+undocumented_function(<a href="#undocumented_function-a">a</a>, <a href="#undocumented_function-b">b</a>, <a href="#undocumented_function-c">c</a>)
+</pre>
+
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| a |  <p align="center"> - </p>   |  none |
+| b |  <p align="center"> - </p>   |  none |
+| c |  <p align="center"> - </p>   |  none |
+
+
diff --git a/test/testdata/function_basic_test/input.bzl b/test/testdata/function_basic_test/input.bzl
new file mode 100644
index 0000000..721e1d3
--- /dev/null
+++ b/test/testdata/function_basic_test/input.bzl
@@ -0,0 +1,38 @@
+"""A test that verifies basic user function documentation."""
+
+def check_sources(
+        name,
+        required_param,
+        bool_param = True,
+        srcs = [],
+        string_param = "",
+        int_param = 2,
+        dict_param = {},
+        struct_param = struct(foo = "bar")):
+    # buildifier: disable=function-docstring-args
+    """Runs some checks on the given source files.
+
+    This rule runs checks on a given set of source files.
+    Use `bazel build` to run the check.
+
+    Args:
+        name: A unique name for this rule.
+        required_param: Use your imagination.
+        srcs: Source files to run the checks against.
+        doesnt_exist: A param that doesn't exist (lets hope we still get *some* documentation)
+        int_param: Your favorite number.
+    """
+    _ignore = [
+        name,
+        required_param,
+        bool_param,
+        srcs,
+        string_param,
+        int_param,
+        dict_param,
+        struct_param,
+    ]
+    x = ("Hah. All that documentation but nothing really to see here")
+
+def undocumented_function(a, b, c):
+    pass
diff --git a/test/testdata/generated_bzl_test/dep.bzl.tpl b/test/testdata/generated_bzl_test/dep.bzl.tpl
new file mode 100644
index 0000000..4c8bd78
--- /dev/null
+++ b/test/testdata/generated_bzl_test/dep.bzl.tpl
@@ -0,0 +1,4 @@
+"""Used to generate dep.bzl"""
+
+def my_rule_impl(ctx):
+    return []
diff --git a/test/testdata/generated_bzl_test/golden.md b/test/testdata/generated_bzl_test/golden.md
new file mode 100755
index 0000000..58c5713
--- /dev/null
+++ b/test/testdata/generated_bzl_test/golden.md
@@ -0,0 +1,22 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-first">first</a>, <a href="#my_rule-second">second</a>)
+</pre>
+
+This is my rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  first my_rule doc string   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+
+
diff --git a/test/testdata/generated_bzl_test/input.bzl b/test/testdata/generated_bzl_test/input.bzl
new file mode 100644
index 0000000..bad15f6
--- /dev/null
+++ b/test/testdata/generated_bzl_test/input.bzl
@@ -0,0 +1,16 @@
+"""A direct dependency file of the input file."""
+
+load(":testdata/generated_bzl_test/dep.bzl", "my_rule_impl")
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is my rule. It does stuff.",
+    attrs = {
+        "first": attr.label(
+            mandatory = True,
+            doc = "first my_rule doc string",
+            allow_single_file = True,
+        ),
+        "second": attr.string_dict(mandatory = True),
+    },
+)
diff --git a/test/testdata/html_tables_template_test/golden.md b/test/testdata/html_tables_template_test/golden.md
new file mode 100755
index 0000000..fb92e03
--- /dev/null
+++ b/test/testdata/html_tables_template_test/golden.md
@@ -0,0 +1,195 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#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
+
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+    <tr id="example_rule-name">
+      <td><code>name</code></td>
+      <td>
+        <a href="https://bazel.build/docs/build-ref.html#name">Name</a>; required
+        <p>
+          A unique name for this target.
+        </p>
+      </td>
+    </tr>
+    <tr id="example_rule-first">
+      <td><code>first</code></td>
+      <td>
+        String; optional
+        <p>
+          This is the first attribute
+        </p>
+      </td>
+    </tr>
+    <tr id="example_rule-second">
+      <td><code>second</code></td>
+      <td>
+        String; optional
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+
+<a name="#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
+
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+    <tr id="ExampleProviderInfo-foo">
+      <td><code>foo</code></td>
+      <td>
+        <p>A string representing foo</p>
+      </td>
+    </tr>
+    <tr id="ExampleProviderInfo-bar">
+      <td><code>bar</code></td>
+      <td>
+        <p>A string representing bar</p>
+      </td>
+    </tr>
+    <tr id="ExampleProviderInfo-baz">
+      <td><code>baz</code></td>
+      <td>
+        <p>A string representing baz</p>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+
+<a name="#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
+
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+    <tr id="example_function-foo">
+      <td><code>foo</code></td>
+      <td>
+        required.
+        <p>
+          This parameter does foo related things.
+        </p>
+      </td>
+    </tr>
+    <tr id="example_function-bar">
+      <td><code>bar</code></td>
+      <td>
+        optional. default is <code>"bar"</code>
+        <p>
+          This parameter does bar related things.
+        </p>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+
+<a name="#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
+
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+    <tr id="example_aspect-deps">
+      <td><code>deps</code></td>
+      <td>
+        String; required.
+    <tr id="example_aspect-attr_aspect">
+      <td><code>attr_aspect</code></td>
+      <td>
+        String; required.
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+### Attributes
+
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+    <tr id="example_aspect-name">
+      <td><code>name</code></td>
+      <td>
+        <a href="https://bazel.build/docs/build-ref.html#name">Name</a>; required
+        <p>
+          A unique name for this target.
+        </p>
+      </td>
+    </tr>
+    <tr id="example_aspect-first">
+      <td><code>first</code></td>
+      <td>
+        <a href="https://bazel.build/docs/build-ref.html#labels">Label</a>; required
+      </td>
+    </tr>
+    <tr id="example_aspect-second">
+      <td><code>second</code></td>
+      <td>
+        String; optional
+        <p>
+          This is the second attribute.
+        </p>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+
diff --git a/test/testdata/html_tables_template_test/input.bzl b/test/testdata/html_tables_template_test/input.bzl
new file mode 100644
index 0000000..23f3379
--- /dev/null
+++ b/test/testdata/html_tables_template_test/input.bzl
@@ -0,0 +1,44 @@
+"""Input file for markdown template test"""
+
+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.
+    """
+    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",
+    },
+)
+
+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"),
+    },
+)
+
+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/input_template_test/aspect.vm b/test/testdata/input_template_test/aspect.vm
new file mode 100644
index 0000000..41b08e5
--- /dev/null
+++ b/test/testdata/input_template_test/aspect.vm
@@ -0,0 +1,32 @@
+<a name="#${aspectName}"></a>
+
+#[[##]]# ${aspectName}
+
+<pre>
+${util.aspectSummary($aspectName, $aspectInfo)}
+</pre>
+
+$aspectInfo.getDocString()
+
+#[[###]]# Aspect Attributes
+
+#if (!$aspectInfo.getAspectAttributeList().isEmpty())
+#foreach ($aspectAttribute in $aspectInfo.getAspectAttributeList())
+        $aspectAttribute
+        String; required.
+#end
+#end
+
+#[[###]]# Attributes
+
+#foreach ($attribute in $aspectInfo.getAttributeList())
+<b>
+      <code>${attribute.name}</code>
+        ${util.attributeTypeString($attribute)}; ${util.mandatoryString($attribute)}
+</b>
+#if (!$attribute.docString.isEmpty())
+        <p>
+          ${attribute.docString.trim()}
+        </p>
+#end
+#end
\ No newline at end of file
diff --git a/test/testdata/input_template_test/func.vm b/test/testdata/input_template_test/func.vm
new file mode 100644
index 0000000..80ef25c
--- /dev/null
+++ b/test/testdata/input_template_test/func.vm
@@ -0,0 +1,29 @@
+<a name="#${funcInfo.functionName}"></a>
+
+#[[##]]# ${funcInfo.functionName}
+
+<pre>
+${util.funcSummary($funcInfo)}
+</pre>
+
+${funcInfo.docString}
+
+<b>input_template_test BOLD PARAMETERS</b>
+
+#if (!$funcInfo.getParameterList().isEmpty())
+#[[###]]# Parameters
+
+#foreach ($param in $funcInfo.getParameterList())
+<b>
+      <code>${param.name}</code>
+        ${util.mandatoryString($param)}.#if(!$param.getDefaultValue().isEmpty()) default is
+        <code>$param.getDefaultValue()</code>
+        </b>
+        #end
+#if (!$param.docString.isEmpty())
+        <p>
+          ${param.docString.trim()}
+        </p>
+#end
+#end
+#end
diff --git a/test/testdata/input_template_test/golden.md b/test/testdata/input_template_test/golden.md
new file mode 100755
index 0000000..aff43e1
--- /dev/null
+++ b/test/testdata/input_template_test/golden.md
@@ -0,0 +1,138 @@
+<!-- THIS HEADER IS FOR input_template_test ONLY -->
+
+Module Docstring: "Input file for input template test"
+
+<a name="#my_example"></a>
+
+## my_example
+
+<pre>
+my_example(<a href="#my_example-name">name</a>, <a href="#my_example-useless">useless</a>)
+</pre>
+
+Small example of rule using chosen template.
+
+<b>input_template_test BOLD ATTRIBUTES</b>
+
+### Attributes
+
+
+<b>
+      <code>name</code>
+        <a href="https://bazel.build/docs/build-ref.html#name">Name</a>; required
+</b>
+        <p>
+          A unique name for this target.
+        </p>
+<b>
+      <code>useless</code>
+        String; optional
+</b>
+        <p>
+          This argument will be ignored.
+        </p>
+
+
+<a name="#example"></a>
+
+## example
+
+<pre>
+example(<a href="#example-foo">foo</a>, <a href="#example-bar">bar</a>, <a href="#example-baz">baz</a>)
+</pre>
+
+Stores information about an example in chosen template.
+
+<b>input_template_test BOLD FIELDS</b>
+
+### Fields
+
+<b>
+      <code>foo</code>
+</b>
+        <p>A string representing foo</p>
+<b>
+      <code>bar</code>
+</b>
+        <p>A string representing bar</p>
+<b>
+      <code>baz</code>
+</b>
+        <p>A string representing baz</p>
+
+
+<a name="#my_aspect_impl"></a>
+
+## my_aspect_impl
+
+<pre>
+my_aspect_impl(<a href="#my_aspect_impl-ctx">ctx</a>)
+</pre>
+
+
+
+<b>input_template_test BOLD PARAMETERS</b>
+
+### Parameters
+
+<b>
+      <code>ctx</code>
+        required.
+
+<a name="#template_function"></a>
+
+## template_function
+
+<pre>
+template_function(<a href="#template_function-foo">foo</a>)
+</pre>
+
+Runs some checks on the given function parameter.
+
+This rule runs checks on a given function parameter in chosen template.
+Use `bazel build` to run the check.
+
+
+<b>input_template_test BOLD PARAMETERS</b>
+
+### Parameters
+
+<b>
+      <code>foo</code>
+        required.        <p>
+          A unique name for this function.
+        </p>
+
+
+<a name="#my_aspect"></a>
+
+## my_aspect
+
+<pre>
+my_aspect(<a href="#my_aspect-name">name</a>, <a href="#my_aspect-first">first</a>)
+</pre>
+
+This is my aspect. It does stuff.
+
+### Aspect Attributes
+
+        deps
+        String; required.
+        attr_aspect
+        String; required.
+
+### Attributes
+
+<b>
+      <code>name</code>
+        <a href="https://bazel.build/docs/build-ref.html#name">Name</a>; required
+</b>
+        <p>
+          A unique name for this target.
+        </p>
+<b>
+      <code>first</code>
+        <a href="https://bazel.build/docs/build-ref.html#labels">Label</a>; required
+</b>
+
+
diff --git a/test/testdata/input_template_test/header.vm b/test/testdata/input_template_test/header.vm
new file mode 100644
index 0000000..2203c76
--- /dev/null
+++ b/test/testdata/input_template_test/header.vm
@@ -0,0 +1,3 @@
+<!-- THIS HEADER IS FOR input_template_test ONLY -->
+
+Module Docstring: "${moduleDocstring}"
diff --git a/test/testdata/input_template_test/input.bzl b/test/testdata/input_template_test/input.bzl
new file mode 100644
index 0000000..37fee12
--- /dev/null
+++ b/test/testdata/input_template_test/input.bzl
@@ -0,0 +1,47 @@
+"""Input file for input template test"""
+
+def template_function(foo):
+    """Runs some checks on the given function parameter.
+
+    This rule runs checks on a given function parameter in chosen template.
+    Use `bazel build` to run the check.
+
+    Args:
+        foo: A unique name for this function.
+    """
+    pass
+
+example = provider(
+    doc = "Stores information about an example in chosen template.",
+    fields = {
+        "foo": "A string representing foo",
+        "bar": "A string representing bar",
+        "baz": "A string representing baz",
+    },
+)
+
+def _rule_impl(ctx):
+    return []
+
+my_example = rule(
+    implementation = _rule_impl,
+    doc = "Small example of rule using chosen template.",
+    attrs = {
+        "useless": attr.string(
+            doc = "This argument will be ignored.",
+            default = "word",
+        ),
+    },
+)
+
+def my_aspect_impl(ctx):
+    return []
+
+my_aspect = aspect(
+    implementation = my_aspect_impl,
+    doc = "This is my aspect. It does stuff.",
+    attr_aspects = ["deps", "attr_aspect"],
+    attrs = {
+        "first": attr.label(mandatory = True, allow_single_file = True),
+    },
+)
diff --git a/test/testdata/input_template_test/provider.vm b/test/testdata/input_template_test/provider.vm
new file mode 100644
index 0000000..269a894
--- /dev/null
+++ b/test/testdata/input_template_test/provider.vm
@@ -0,0 +1,22 @@
+<a name="#${providerName}"></a>
+
+#[[##]]# ${providerName}
+
+<pre>
+${util.providerSummary($providerName, $providerInfo)}
+</pre>
+
+${providerInfo.docString}
+
+<b>input_template_test BOLD FIELDS</b>
+
+#if (!$providerInfo.fieldInfoList.isEmpty())
+#[[###]]# Fields
+
+#foreach ($field in $providerInfo.fieldInfoList)
+<b>
+      <code>${field.name}</code>
+</b>
+        <p>${field.docString}</p>
+#end
+#end
diff --git a/test/testdata/input_template_test/rule.vm b/test/testdata/input_template_test/rule.vm
new file mode 100644
index 0000000..2227637
--- /dev/null
+++ b/test/testdata/input_template_test/rule.vm
@@ -0,0 +1,28 @@
+<a name="#${ruleName}"></a>
+
+#[[##]]# ${ruleName}
+
+<pre>
+${util.ruleSummary($ruleName, $ruleInfo)}
+</pre>
+
+${ruleInfo.docString}
+
+<b>input_template_test BOLD ATTRIBUTES</b>
+
+#[[###]]# Attributes
+
+#if (!$ruleInfo.getAttributeList().isEmpty())
+
+#foreach ($attribute in $ruleInfo.getAttributeList())
+<b>
+      <code>${attribute.name}</code>
+        ${util.attributeTypeString($attribute)}; ${util.mandatoryString($attribute)}
+</b>
+#if (!$attribute.docString.isEmpty())
+        <p>
+          ${attribute.docString.trim()}
+        </p>
+#end
+#end
+#end
diff --git a/test/testdata/java_basic_test/golden.md b/test/testdata/java_basic_test/golden.md
new file mode 100755
index 0000000..73fef60
--- /dev/null
+++ b/test/testdata/java_basic_test/golden.md
@@ -0,0 +1,24 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#java_related_rule"></a>
+
+## java_related_rule
+
+<pre>
+java_related_rule(<a href="#java_related_rule-name">name</a>, <a href="#java_related_rule-first">first</a>, <a href="#java_related_rule-fourth">fourth</a>, <a href="#java_related_rule-second">second</a>, <a href="#java_related_rule-third">third</a>)
+</pre>
+
+This rule does java-related things.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| fourth |  -   | Boolean | optional | False |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| third |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
diff --git a/test/testdata/java_basic_test/input.bzl b/test/testdata/java_basic_test/input.bzl
new file mode 100644
index 0000000..db0d064
--- /dev/null
+++ b/test/testdata/java_basic_test/input.bzl
@@ -0,0 +1,22 @@
+# buildifier: disable=module-docstring
+# buildifier: disable=function-docstring
+def exercise_the_api():
+    var1 = java_common.JavaRuntimeInfo
+    var2 = JavaInfo
+    var3 = java_proto_common
+
+exercise_the_api()
+
+def my_rule_impl(ctx):
+    return []
+
+java_related_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This rule does java-related things.",
+    attrs = {
+        "first": attr.label(mandatory = True, allow_single_file = True),
+        "second": attr.string_dict(mandatory = True),
+        "third": attr.output(mandatory = True),
+        "fourth": attr.bool(default = False, mandatory = False),
+    },
+)
diff --git a/test/testdata/local_repository_test/BUILD b/test/testdata/local_repository_test/BUILD
new file mode 100644
index 0000000..05fdc75
--- /dev/null
+++ b/test/testdata/local_repository_test/BUILD
@@ -0,0 +1,18 @@
+load("@io_bazel_skydoc//stardoc:stardoc.bzl", "stardoc")
+
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+licenses(["notice"])  # Apache 2.0
+
+exports_files([
+    "input.bzl",
+    "golden.md",
+])
+
+stardoc(
+    name = "input_doc",
+    out = "output.md",
+    input = ":input.bzl",
+)
diff --git a/test/testdata/local_repository_test/WORKSPACE b/test/testdata/local_repository_test/WORKSPACE
new file mode 100644
index 0000000..9530407
--- /dev/null
+++ b/test/testdata/local_repository_test/WORKSPACE
@@ -0,0 +1 @@
+workspace(name = "local_workspace_test")
diff --git a/test/testdata/local_repository_test/golden.md b/test/testdata/local_repository_test/golden.md
new file mode 100755
index 0000000..ef3e91f
--- /dev/null
+++ b/test/testdata/local_repository_test/golden.md
@@ -0,0 +1,20 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#min"></a>
+
+## min
+
+<pre>
+min(<a href="#min-integers">integers</a>)
+</pre>
+
+Returns the minimum of given elements.
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| integers |  A list of integers. Must not be empty.   |  none |
+
+
diff --git a/test/testdata/local_repository_test/input.bzl b/test/testdata/local_repository_test/input.bzl
new file mode 100644
index 0000000..62f0982
--- /dev/null
+++ b/test/testdata/local_repository_test/input.bzl
@@ -0,0 +1,15 @@
+"""A test that verifies documenting functions in an input file under a local_repository."""
+
+def min(integers):
+    """Returns the minimum of given elements.
+
+    Args:
+      integers: A list of integers. Must not be empty.
+
+    Returns:
+      The minimum integer in the given list.
+    """
+    _ignore = [integers]
+    return 42
+
+
diff --git a/test/testdata/macro_kwargs_test/golden.md b/test/testdata/macro_kwargs_test/golden.md
new file mode 100755
index 0000000..74f9d7d
--- /dev/null
+++ b/test/testdata/macro_kwargs_test/golden.md
@@ -0,0 +1,73 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#macro_with_args"></a>
+
+## macro_with_args
+
+<pre>
+macro_with_args(<a href="#macro_with_args-name">name</a>, <a href="#macro_with_args-args">args</a>)
+</pre>
+
+My args macro is OK.
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| name |  The name of the test rule.   |  none |
+| args |  Other arguments to include   |  none |
+
+
+<a name="#macro_with_both"></a>
+
+## macro_with_both
+
+<pre>
+macro_with_both(<a href="#macro_with_both-name">name</a>, <a href="#macro_with_both-number">number</a>, <a href="#macro_with_both-args">args</a>, <a href="#macro_with_both-kwargs">kwargs</a>)
+</pre>
+
+Oh wow this macro has both.
+
+Not much else to say.
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| name |  The name of the test rule.   |  none |
+| number |  Some number used for important things   |  <code>3</code> |
+| args |  Other arguments to include   |  none |
+| kwargs |  Other attributes to include   |  none |
+
+
+<a name="#macro_with_kwargs"></a>
+
+## macro_with_kwargs
+
+<pre>
+macro_with_kwargs(<a href="#macro_with_kwargs-name">name</a>, <a href="#macro_with_kwargs-config">config</a>, <a href="#macro_with_kwargs-deps">deps</a>, <a href="#macro_with_kwargs-kwargs">kwargs</a>)
+</pre>
+
+My kwargs macro is the best.
+
+This is a long multi-line doc string.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
+elementum, diam vitae tincidunt pulvinar, nunc tortor volutpat dui,
+vitae facilisis odio ligula a tortor. Donec ullamcorper odio eget ipsum tincidunt,
+vel mollis eros pellentesque.
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| name |  The name of the test rule.   |  none |
+| config |  Config to use for my macro   |  none |
+| deps |  List of my macro's dependencies   |  <code>[]</code> |
+| kwargs |  Other attributes to include   |  none |
+
+
diff --git a/test/testdata/macro_kwargs_test/input.bzl b/test/testdata/macro_kwargs_test/input.bzl
new file mode 100644
index 0000000..0f6268d
--- /dev/null
+++ b/test/testdata/macro_kwargs_test/input.bzl
@@ -0,0 +1,52 @@
+"""Tests for functions which use *args or **kwargs"""
+
+def macro_with_kwargs(name, config, deps = [], **kwargs):
+    """My kwargs macro is the best.
+
+    This is a long multi-line doc string.
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
+    elementum, diam vitae tincidunt pulvinar, nunc tortor volutpat dui,
+    vitae facilisis odio ligula a tortor. Donec ullamcorper odio eget ipsum tincidunt,
+    vel mollis eros pellentesque.
+
+    Args:
+      name: The name of the test rule.
+      config: Config to use for my macro
+      deps: List of my macro's dependencies
+      **kwargs: Other attributes to include
+
+    Returns:
+      An empty list.
+    """
+    _ignore = [name, config, deps, kwargs]
+    return []
+
+def macro_with_args(name, *args):
+    """My args macro is OK.
+
+    Args:
+      name: The name of the test rule.
+      *args: Other arguments to include
+
+    Returns:
+      An empty list.
+    """
+    _ignore = [name, args]
+    return []
+
+def macro_with_both(name, number = 3, *args, **kwargs):
+    """Oh wow this macro has both.
+
+    Not much else to say.
+
+    Args:
+      name: The name of the test rule.
+      number: Some number used for important things
+      *args: Other arguments to include
+      **kwargs: Other attributes to include
+
+    Returns:
+      An empty list.
+    """
+    _ignore = [name, number, args, kwargs]
+    return []
diff --git a/test/testdata/misc_apis_test/golden.md b/test/testdata/misc_apis_test/golden.md
new file mode 100755
index 0000000..2a93a2f
--- /dev/null
+++ b/test/testdata/misc_apis_test/golden.md
@@ -0,0 +1,76 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## 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>)
+</pre>
+
+This rule exercises some of the build API.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| deps |  A list of dependencies.   | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
+| extra_arguments |  -   | List of strings | optional | [] |
+| out |  The output file.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| src |  The source file.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
+| tool |  The location of the tool to use.   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | //foo/bar/baz:target |
+
+
+<a name="#MyInfo"></a>
+
+## MyInfo
+
+<pre>
+MyInfo(<a href="#MyInfo-foo">foo</a>, <a href="#MyInfo-bar">bar</a>)
+</pre>
+
+
+
+**FIELDS**
+
+
+| Name  | Description |
+| :-------------: | :-------------: |
+| foo |  Something foo-related.    |
+| bar |  Something bar-related.    |
+
+
+<a name="#exercise_the_api"></a>
+
+## exercise_the_api
+
+<pre>
+exercise_the_api()
+</pre>
+
+
+
+**PARAMETERS**
+
+
+
+<a name="#my_rule_impl"></a>
+
+## my_rule_impl
+
+<pre>
+my_rule_impl(<a href="#my_rule_impl-ctx">ctx</a>)
+</pre>
+
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| ctx |  <p align="center"> - </p>   |  none |
+
+
diff --git a/test/testdata/misc_apis_test/input.bzl b/test/testdata/misc_apis_test/input.bzl
new file mode 100644
index 0000000..943442f
--- /dev/null
+++ b/test/testdata/misc_apis_test/input.bzl
@@ -0,0 +1,57 @@
+# This is here to test that built-in names can be shadowed by global names.
+# (Regression test for http://b/35984389).
+# buildifier: disable=module-docstring
+config = "value for global config variable"
+
+def my_rule_impl(ctx):
+    return []
+
+def exercise_the_api():
+    var1 = config_common.FeatureFlagInfo
+    var2 = platform_common.TemplateVariableInfo
+    var3 = repository_rule(
+        implementation = my_rule_impl,
+        doc = "This repository rule has documentation.",
+    )
+    var4 = testing.ExecutionInfo({})
+
+exercise_the_api()
+
+MyInfo = provider(
+    fields = {
+        "foo": "Something foo-related.",
+        "bar": "Something bar-related.",
+    },
+)
+
+my_info = MyInfo(foo = "x", bar = "y")
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This rule exercises some of the build API.",
+    attrs = {
+        "src": attr.label(
+            doc = "The source file.",
+            allow_files = [".bzl"],
+        ),
+        "deps": attr.label_list(
+            doc = """
+A list of dependencies.
+""",
+            providers = [MyInfo],
+            allow_files = False,
+        ),
+        "tool": attr.label(
+            doc = "The location of the tool to use.",
+            allow_files = True,
+            default = Label("//foo/bar/baz:target"),
+            cfg = "host",
+            executable = True,
+        ),
+        "out": attr.output(
+            doc = "The output file.",
+            mandatory = True,
+        ),
+        "extra_arguments": attr.string_list(default = []),
+    },
+)
diff --git a/test/testdata/multi_level_namespace_test/golden.md b/test/testdata/multi_level_namespace_test/golden.md
new file mode 100755
index 0000000..d036b1a
--- /dev/null
+++ b/test/testdata/multi_level_namespace_test/golden.md
@@ -0,0 +1,84 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#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 |
+| :-------------: | :-------------: | :-------------: |
+| integers |  A list of integers. Must not be empty.   |  none |
+
+
+<a name="#my_namespace.math.min"></a>
+
+## my_namespace.math.min
+
+<pre>
+my_namespace.math.min(<a href="#my_namespace.math.min-integers">integers</a>)
+</pre>
+
+Returns the minimum of given elements.
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| integers |  A list of integers. Must not be empty.   |  none |
+
+
+<a name="#my_namespace.foo.bar.baz"></a>
+
+## my_namespace.foo.bar.baz
+
+<pre>
+my_namespace.foo.bar.baz()
+</pre>
+
+This function does nothing.
+
+**PARAMETERS**
+
+
+
+<a name="#my_namespace.one.two.min"></a>
+
+## my_namespace.one.two.min
+
+<pre>
+my_namespace.one.two.min(<a href="#my_namespace.one.two.min-integers">integers</a>)
+</pre>
+
+Returns the minimum of given elements.
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| integers |  A list of integers. Must not be empty.   |  none |
+
+
+<a name="#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.
+
+**PARAMETERS**
+
+
+
diff --git a/test/testdata/multi_level_namespace_test/input.bzl b/test/testdata/multi_level_namespace_test/input.bzl
new file mode 100644
index 0000000..8b0b436
--- /dev/null
+++ b/test/testdata/multi_level_namespace_test/input.bzl
@@ -0,0 +1,32 @@
+"""A test that verifies documenting a multi-leveled namespace of functions."""
+
+def _min(integers):
+    """Returns the minimum of given elements.
+
+    Args:
+      integers: A list of integers. Must not be empty.
+
+    Returns:
+      The minimum integer in the given list.
+    """
+    _ignore = [integers]
+    return 42
+
+def _does_nothing():
+    """This function does nothing."""
+    pass
+
+my_namespace = struct(
+    dropped_field = "Note this field should not be documented",
+    min = _min,
+    math = struct(min = _min),
+    foo = struct(
+        bar = struct(baz = _does_nothing),
+        num = 12,
+        string = "Hello!",
+    ),
+    one = struct(
+        two = struct(min = _min),
+        three = struct(does_nothing = _does_nothing),
+    ),
+)
diff --git a/test/testdata/multi_level_namespace_test_with_whitelist/golden.md b/test/testdata/multi_level_namespace_test_with_whitelist/golden.md
new file mode 100644
index 0000000..829b96b
--- /dev/null
+++ b/test/testdata/multi_level_namespace_test_with_whitelist/golden.md
@@ -0,0 +1,52 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#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 |
+| :-------------: | :-------------: | :-------------: |
+| integers |  <p align="center"> - </p>   |  none |
+
+
+<a name="#my_namespace.math.min"></a>
+
+## my_namespace.math.min
+
+<pre>
+my_namespace.math.min(<a href="#my_namespace.math.min-integers">integers</a>)
+</pre>
+
+Returns the minimum of given elements.
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| integers |  <p align="center"> - </p>   |  none |
+
+
+<a name="#other_namespace.foo.nothing"></a>
+
+## other_namespace.foo.nothing
+
+<pre>
+other_namespace.foo.nothing()
+</pre>
+
+This function does nothing.
+
+**PARAMETERS**
+
+
+
diff --git a/test/testdata/multi_level_namespace_test_with_whitelist/input.bzl b/test/testdata/multi_level_namespace_test_with_whitelist/input.bzl
new file mode 100644
index 0000000..34eb87b
--- /dev/null
+++ b/test/testdata/multi_level_namespace_test_with_whitelist/input.bzl
@@ -0,0 +1,23 @@
+"""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
+specific symbol in other_namespace to be documented."""
+
+def _min(integers):
+    """Returns the minimum of given elements."""
+    _ignore = [integers]
+    return 42
+
+def _does_nothing():
+    """This function does nothing."""
+    pass
+
+my_namespace = struct(
+    dropped_field = "Note this field should not be documented",
+    min = _min,
+    math = struct(min = _min),
+)
+
+other_namespace = struct(
+    foo = struct(nothing = _does_nothing),
+    min = _min,
+)
diff --git a/test/testdata/multiple_files_test/dep.bzl b/test/testdata/multiple_files_test/dep.bzl
new file mode 100644
index 0000000..b1beece
--- /dev/null
+++ b/test/testdata/multiple_files_test/dep.bzl
@@ -0,0 +1,17 @@
+"""A dependency file for multiple_files_test."""
+
+load(":testdata/multiple_files_test/inner_dep.bzl", "inner_rule_impl", "prep_work")
+
+def some_cool_function(name, srcs = [], beef = ""):
+    """A pretty cool function. You should call it.
+
+    Args:
+      name: Some sort of name.
+      srcs: What sources you want cool stuff to happen to.
+      beef: Your opinion on beef.
+    """
+    x = (name, srcs, beef)
+
+prep_work()
+
+my_rule_impl = inner_rule_impl
diff --git a/test/testdata/multiple_files_test/golden.md b/test/testdata/multiple_files_test/golden.md
new file mode 100755
index 0000000..a6ca7f0
--- /dev/null
+++ b/test/testdata/multiple_files_test/golden.md
@@ -0,0 +1,81 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-first">first</a>, <a href="#my_rule-second">second</a>)
+</pre>
+
+This is my rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  first my_rule doc string   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+
+
+<a name="#other_rule"></a>
+
+## other_rule
+
+<pre>
+other_rule(<a href="#other_rule-name">name</a>, <a href="#other_rule-fourth">fourth</a>, <a href="#other_rule-third">third</a>)
+</pre>
+
+This is another rule.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| fourth |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| third |  third other_rule doc string   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
+<a name="#yet_another_rule"></a>
+
+## yet_another_rule
+
+<pre>
+yet_another_rule(<a href="#yet_another_rule-name">name</a>, <a href="#yet_another_rule-fifth">fifth</a>)
+</pre>
+
+This is yet another rule
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| fifth |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
+<a name="#top_fun"></a>
+
+## top_fun
+
+<pre>
+top_fun(<a href="#top_fun-a">a</a>, <a href="#top_fun-b">b</a>, <a href="#top_fun-c">c</a>)
+</pre>
+
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| a |  <p align="center"> - </p>   |  none |
+| b |  <p align="center"> - </p>   |  none |
+| c |  <p align="center"> - </p>   |  none |
+
+
diff --git a/test/testdata/multiple_files_test/inner_dep.bzl b/test/testdata/multiple_files_test/inner_dep.bzl
new file mode 100644
index 0000000..16d4361
--- /dev/null
+++ b/test/testdata/multiple_files_test/inner_dep.bzl
@@ -0,0 +1,9 @@
+"""A deep dependency file."""
+
+def prep_work():
+    """Does some prep work. Nothing to see here."""
+    return 1
+
+def inner_rule_impl(ctx):
+    _ignore = [ctx]
+    return struct()
diff --git a/test/testdata/multiple_files_test/input.bzl b/test/testdata/multiple_files_test/input.bzl
new file mode 100644
index 0000000..5b46c54
--- /dev/null
+++ b/test/testdata/multiple_files_test/input.bzl
@@ -0,0 +1,41 @@
+"""A direct dependency file of the input file."""
+
+load(":testdata/multiple_files_test/dep.bzl", "my_rule_impl", "some_cool_function")
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is my rule. It does stuff.",
+    attrs = {
+        "first": attr.label(
+            mandatory = True,
+            doc = "first my_rule doc string",
+            allow_single_file = True,
+        ),
+        "second": attr.string_dict(mandatory = True),
+    },
+)
+
+def top_fun(a, b, c):
+    some_cool_function(a, b, c)
+    return 6
+
+other_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is another rule.",
+    attrs = {
+        "third": attr.label(
+            mandatory = True,
+            doc = "third other_rule doc string",
+            allow_single_file = True,
+        ),
+        "fourth": attr.string_dict(mandatory = True),
+    },
+)
+
+yet_another_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is yet another rule",
+    attrs = {
+        "fifth": attr.label(mandatory = True, allow_single_file = True),
+    },
+)
diff --git a/test/testdata/multiple_rules_test/golden.md b/test/testdata/multiple_rules_test/golden.md
new file mode 100755
index 0000000..ca4f407
--- /dev/null
+++ b/test/testdata/multiple_rules_test/golden.md
@@ -0,0 +1,79 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-first">first</a>, <a href="#my_rule-second">second</a>)
+</pre>
+
+This is my rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+
+
+<a name="#other_rule"></a>
+
+## other_rule
+
+<pre>
+other_rule(<a href="#other_rule-name">name</a>, <a href="#other_rule-fourth">fourth</a>, <a href="#other_rule-third">third</a>)
+</pre>
+
+This is another rule.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| fourth |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| third |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
+<a name="#yet_another_rule"></a>
+
+## yet_another_rule
+
+<pre>
+yet_another_rule(<a href="#yet_another_rule-name">name</a>, <a href="#yet_another_rule-fifth">fifth</a>)
+</pre>
+
+This is yet another rule
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| fifth |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
+<a name="#my_rule_impl"></a>
+
+## my_rule_impl
+
+<pre>
+my_rule_impl(<a href="#my_rule_impl-ctx">ctx</a>)
+</pre>
+
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| ctx |  <p align="center"> - </p>   |  none |
+
+
diff --git a/test/testdata/multiple_rules_test/input.bzl b/test/testdata/multiple_rules_test/input.bzl
new file mode 100644
index 0000000..7a2d314
--- /dev/null
+++ b/test/testdata/multiple_rules_test/input.bzl
@@ -0,0 +1,31 @@
+# buildifier: disable=module-docstring
+def my_rule_impl(ctx):
+    return []
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is my rule. It does stuff.",
+    attrs = {
+        "first": attr.label(mandatory = True, allow_single_file = True),
+        "second": attr.string_dict(mandatory = True),
+    },
+)
+
+other_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is another rule.",
+    attrs = {
+        "third": attr.label(mandatory = True, allow_single_file = True),
+        "_hidden": attr.string(),
+        "fourth": attr.string_dict(mandatory = True),
+    },
+)
+
+yet_another_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is yet another rule",
+    attrs = {
+        "_hidden": attr.string(),
+        "fifth": attr.label(mandatory = True, allow_single_file = True),
+    },
+)
diff --git a/test/testdata/namespace_test/golden.md b/test/testdata/namespace_test/golden.md
new file mode 100755
index 0000000..a26526d
--- /dev/null
+++ b/test/testdata/namespace_test/golden.md
@@ -0,0 +1,58 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_namespace.assert_non_empty"></a>
+
+## my_namespace.assert_non_empty
+
+<pre>
+my_namespace.assert_non_empty(<a href="#my_namespace.assert_non_empty-some_list">some_list</a>, <a href="#my_namespace.assert_non_empty-other_list">other_list</a>)
+</pre>
+
+Asserts the two given lists are not empty.
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| some_list |  The first list   |  none |
+| other_list |  The second list   |  none |
+
+
+<a name="#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 |
+| :-------------: | :-------------: | :-------------: |
+| integers |  A list of integers. Must not be empty.   |  none |
+
+
+<a name="#my_namespace.join_strings"></a>
+
+## my_namespace.join_strings
+
+<pre>
+my_namespace.join_strings(<a href="#my_namespace.join_strings-strings">strings</a>, <a href="#my_namespace.join_strings-delimiter">delimiter</a>)
+</pre>
+
+Joins the given strings with a delimiter.
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| strings |  A list of strings to join.   |  none |
+| delimiter |  The delimiter to use   |  <code>", "</code> |
+
+
diff --git a/test/testdata/namespace_test/input.bzl b/test/testdata/namespace_test/input.bzl
new file mode 100644
index 0000000..69cad64
--- /dev/null
+++ b/test/testdata/namespace_test/input.bzl
@@ -0,0 +1,43 @@
+"""A test that verifies documenting a namespace of functions."""
+
+def _min(integers):
+    """Returns the minimum of given elements.
+
+    Args:
+      integers: A list of integers. Must not be empty.
+
+    Returns:
+      The minimum integer in the given list.
+    """
+    _ignore = [integers]
+    return 42
+
+def _assert_non_empty(some_list, other_list):
+    """Asserts the two given lists are not empty.
+
+    Args:
+      some_list: The first list
+      other_list: The second list
+    """
+    _ignore = [some_list, other_list]
+    fail("Not implemented")
+
+def _join_strings(strings, delimiter = ", "):
+    """Joins the given strings with a delimiter.
+
+    Args:
+      strings: A list of strings to join.
+      delimiter: The delimiter to use
+
+    Returns:
+      The joined string.
+    """
+    _ignore = [strings, delimiter]
+    return ""
+
+my_namespace = struct(
+    dropped_field = "Note this field should not be documented",
+    assert_non_empty = _assert_non_empty,
+    min = _min,
+    join_strings = _join_strings,
+)
diff --git a/test/testdata/proto_format_test/golden.raw b/test/testdata/proto_format_test/golden.raw
new file mode 100644
index 0000000..d158834
--- /dev/null
+++ b/test/testdata/proto_format_test/golden.raw
@@ -0,0 +1,17 @@
+
+‰
+
+my_exampleSmall example of rule.*
+nameA unique name for this target. 7
+uselessThis argument will be ignored.2
+"ignoreme"•
+example$Stores information about an example. 
+fooA string representing foo 
+barA string representing bar 
+bazA string representing bazÆ
+check_function%
+fooA unique name for this rule. ŒRuns some checks on the given function parameter.
+
+This rule runs checks on a given function parameter.
+Use `bazel build` to run the check.
+* Input file for proto format test
\ No newline at end of file
diff --git a/test/testdata/proto_format_test/input.bzl b/test/testdata/proto_format_test/input.bzl
new file mode 100644
index 0000000..aee171e
--- /dev/null
+++ b/test/testdata/proto_format_test/input.bzl
@@ -0,0 +1,35 @@
+"""Input file for proto format test"""
+
+def check_function(foo):
+    """Runs some checks on the given function parameter.
+
+    This rule runs checks on a given function parameter.
+    Use `bazel build` to run the check.
+
+    Args:
+        foo: A unique name for this rule.
+    """
+    pass
+
+example = provider(
+    doc = "Stores information about an example.",
+    fields = {
+        "foo": "A string representing foo",
+        "bar": "A string representing bar",
+        "baz": "A string representing baz",
+    },
+)
+
+def _rule_impl(ctx):
+    return []
+
+my_example = rule(
+    implementation = _rule_impl,
+    doc = "Small example of rule.",
+    attrs = {
+        "useless": attr.string(
+            doc = "This argument will be ignored.",
+            default = "ignoreme",
+        ),
+    },
+)
diff --git a/test/testdata/provider_basic_test/golden.md b/test/testdata/provider_basic_test/golden.md
new file mode 100755
index 0000000..2154f34
--- /dev/null
+++ b/test/testdata/provider_basic_test/golden.md
@@ -0,0 +1,57 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#MyFooInfo"></a>
+
+## MyFooInfo
+
+<pre>
+MyFooInfo(<a href="#MyFooInfo-bar">bar</a>, <a href="#MyFooInfo-baz">baz</a>)
+</pre>
+
+Stores information about a foo.
+
+**FIELDS**
+
+
+| Name  | Description |
+| :-------------: | :-------------: |
+| bar |  (Undocumented)    |
+| baz |  (Undocumented)    |
+
+
+<a name="#MyPoorlyDocumentedInfo"></a>
+
+## MyPoorlyDocumentedInfo
+
+<pre>
+MyPoorlyDocumentedInfo()
+</pre>
+
+
+
+**FIELDS**
+
+
+
+<a name="#MyVeryDocumentedInfo"></a>
+
+## MyVeryDocumentedInfo
+
+<pre>
+MyVeryDocumentedInfo(<a href="#MyVeryDocumentedInfo-favorite_food">favorite_food</a>, <a href="#MyVeryDocumentedInfo-favorite_color">favorite_color</a>)
+</pre>
+
+
+A provider with some really neat documentation.
+Look on my works, ye mighty, and despair!
+
+
+**FIELDS**
+
+
+| Name  | Description |
+| :-------------: | :-------------: |
+| favorite_food |  A string representing my favorite food    |
+| favorite_color |  A string representing my favorite color    |
+
+
diff --git a/test/testdata/provider_basic_test/input.bzl b/test/testdata/provider_basic_test/input.bzl
new file mode 100644
index 0000000..7600f2c
--- /dev/null
+++ b/test/testdata/provider_basic_test/input.bzl
@@ -0,0 +1,18 @@
+# buildifier: disable=module-docstring
+MyPoorlyDocumentedInfo = provider()
+
+MyFooInfo = provider(
+    doc = "Stores information about a foo.",
+    fields = ["bar", "baz"],
+)
+
+MyVeryDocumentedInfo = provider(
+    doc = """
+A provider with some really neat documentation.
+Look on my works, ye mighty, and despair!
+""",
+    fields = {
+        "favorite_food": "A string representing my favorite food",
+        "favorite_color": "A string representing my favorite color",
+    },
+)
diff --git a/test/testdata/providers_for_attributes_test/dep.bzl b/test/testdata/providers_for_attributes_test/dep.bzl
new file mode 100644
index 0000000..56ab3b7
--- /dev/null
+++ b/test/testdata/providers_for_attributes_test/dep.bzl
@@ -0,0 +1,5 @@
+"A file to test providers not defined in the same file."
+
+DepProviderInfo = provider(
+    doc = "This provider does something.",
+)
diff --git a/test/testdata/providers_for_attributes_test/golden.md b/test/testdata/providers_for_attributes_test/golden.md
new file mode 100755
index 0000000..9f1dd2b
--- /dev/null
+++ b/test/testdata/providers_for_attributes_test/golden.md
@@ -0,0 +1,77 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-fifth">fifth</a>, <a href="#my_rule-first">first</a>, <a href="#my_rule-fourth">fourth</a>, <a href="#my_rule-second">second</a>, <a href="#my_rule-sixth">sixth</a>, <a href="#my_rule-third">third</a>)
+</pre>
+
+This rule does things.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| fifth |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
+| first |  this is the first attribute.   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: Label -> String</a> | optional | {} |
+| fourth |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
+| second |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
+| sixth |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
+| third |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
+
+
+<a name="#MyProviderInfo"></a>
+
+## MyProviderInfo
+
+<pre>
+MyProviderInfo(<a href="#MyProviderInfo-foo">foo</a>, <a href="#MyProviderInfo-bar">bar</a>)
+</pre>
+
+
+
+**FIELDS**
+
+
+| Name  | Description |
+| :-------------: | :-------------: |
+| foo |  Something foo-related.    |
+| bar |  Something bar-related.    |
+
+
+<a name="#OtherProviderInfo"></a>
+
+## OtherProviderInfo
+
+<pre>
+OtherProviderInfo()
+</pre>
+
+
+
+**FIELDS**
+
+
+
+<a name="#my_rule_impl"></a>
+
+## my_rule_impl
+
+<pre>
+my_rule_impl(<a href="#my_rule_impl-ctx">ctx</a>)
+</pre>
+
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| ctx |  <p align="center"> - </p>   |  none |
+
+
diff --git a/test/testdata/providers_for_attributes_test/input.bzl b/test/testdata/providers_for_attributes_test/input.bzl
new file mode 100644
index 0000000..284852d
--- /dev/null
+++ b/test/testdata/providers_for_attributes_test/input.bzl
@@ -0,0 +1,43 @@
+"""The input file for the providers for attributes test"""
+
+load(":testdata/providers_for_attributes_test/dep.bzl", "DepProviderInfo")
+
+def my_rule_impl(ctx):
+    return []
+
+MyProviderInfo = provider(
+    fields = {
+        "foo": "Something foo-related.",
+        "bar": "Something bar-related.",
+    },
+)
+
+OtherProviderInfo = provider()
+other_provider_info = OtherProviderInfo(fields = ["foo"])
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This rule does things.",
+    attrs = {
+        "first": attr.label_keyed_string_dict(
+            providers = [MyProviderInfo, PyInfo, cc_common.CcToolchainInfo],
+            doc = "this is the first attribute.",
+        ),
+        "second": attr.label_list(
+            providers = [[CcInfo], [OtherProviderInfo, DepProviderInfo]],
+        ),
+        "third": attr.label(
+            providers = [OtherProviderInfo],
+        ),
+        "fourth": attr.label(
+            # buildifier: disable=native-proto
+            providers = [ProtoInfo, DefaultInfo, JavaInfo],
+        ),
+        "fifth": attr.label(
+            providers = [["LegacyProvider", "ObjectProvider"], [DefaultInfo, JavaInfo]],
+        ),
+        "sixth": attr.label(
+            providers = ["LegacyProvider"],
+        ),
+    },
+)
diff --git a/test/testdata/py_rule_test/golden.md b/test/testdata/py_rule_test/golden.md
new file mode 100755
index 0000000..81b44d8
--- /dev/null
+++ b/test/testdata/py_rule_test/golden.md
@@ -0,0 +1,26 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#py_related_rule"></a>
+
+## py_related_rule
+
+<pre>
+py_related_rule(<a href="#py_related_rule-name">name</a>, <a href="#py_related_rule-fifth">fifth</a>, <a href="#py_related_rule-first">first</a>, <a href="#py_related_rule-fourth">fourth</a>, <a href="#py_related_rule-second">second</a>, <a href="#py_related_rule-sixth">sixth</a>, <a href="#py_related_rule-third">third</a>)
+</pre>
+
+This rule does python-related things.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| fifth |  Hey look, its the fifth thing!   | Boolean | optional | True |
+| first |  this is the first doc string!   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| fourth |  the fourth doc string.   | Boolean | optional | False |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| sixth |  it's the sixth thing.   | List of integers | optional | range(0, 10) |
+| third |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
diff --git a/test/testdata/py_rule_test/input.bzl b/test/testdata/py_rule_test/input.bzl
new file mode 100644
index 0000000..0d6bc16
--- /dev/null
+++ b/test/testdata/py_rule_test/input.bzl
@@ -0,0 +1,32 @@
+"""The input file for the python rule test"""
+
+def exercise_the_api():
+    var1 = PyRuntimeInfo
+    var2 = PyInfo
+
+exercise_the_api()
+
+def my_rule_impl(ctx):
+    return []
+
+py_related_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This rule does python-related things.",
+    attrs = {
+        "first": attr.label(
+            mandatory = True,
+            doc = "this is the first doc string!",
+            allow_single_file = True,
+        ),
+        "second": attr.string_dict(mandatory = True),
+        "third": attr.output(mandatory = True),
+        "fourth": attr.bool(default = False, doc = "the fourth doc string.", mandatory = False),
+        "fifth": attr.bool(default = True, doc = "Hey look, its the fifth thing!"),
+        "sixth": attr.int_list(
+            default = range(10),
+            doc = "it's the sixth thing.",
+            mandatory = False,
+        ),
+        "_hidden": attr.string(),
+    },
+)
diff --git a/test/testdata/repo_rules_test/golden.md b/test/testdata/repo_rules_test/golden.md
new file mode 100755
index 0000000..b40071f
--- /dev/null
+++ b/test/testdata/repo_rules_test/golden.md
@@ -0,0 +1,21 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_repo"></a>
+
+## my_repo
+
+<pre>
+my_repo(<a href="#my_repo-name">name</a>, <a href="#my_repo-useless">useless</a>)
+</pre>
+
+Minimal example of a repository rule.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this repository.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| useless |  This argument will be ingored. You don't have to specify it, but you may.   | String | optional | "ignoreme" |
+
+
diff --git a/test/testdata/repo_rules_test/input.bzl b/test/testdata/repo_rules_test/input.bzl
new file mode 100644
index 0000000..023d92d
--- /dev/null
+++ b/test/testdata/repo_rules_test/input.bzl
@@ -0,0 +1,14 @@
+# buildifier: disable=module-docstring
+def _repo_rule_impl(ctx):
+    ctx.file("BUILD", "")
+
+my_repo = repository_rule(
+    implementation = _repo_rule_impl,
+    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.",
+            default = "ignoreme",
+        ),
+    },
+)
diff --git a/test/testdata/same_level_file_test/BUILD b/test/testdata/same_level_file_test/BUILD
new file mode 100644
index 0000000..0f4f48a
--- /dev/null
+++ b/test/testdata/same_level_file_test/BUILD
@@ -0,0 +1,14 @@
+filegroup(
+    name = "srcs",
+    testonly = 0,
+    srcs = glob(["**"]),
+    visibility = ["//src:__subpackages__"],
+)
+
+exports_files(
+    [
+        "dep.bzl",
+        "golden.md",
+        "input.bzl",
+    ],
+)
diff --git a/test/testdata/same_level_file_test/dep.bzl b/test/testdata/same_level_file_test/dep.bzl
new file mode 100644
index 0000000..87750b3
--- /dev/null
+++ b/test/testdata/same_level_file_test/dep.bzl
@@ -0,0 +1,5 @@
+# buildifier: disable=module-docstring
+# buildifier: disable=function-docstring
+def my_rule_impl(ctx):
+    _ignore = [ctx]
+    return struct()
diff --git a/test/testdata/same_level_file_test/golden.md b/test/testdata/same_level_file_test/golden.md
new file mode 100755
index 0000000..58c5713
--- /dev/null
+++ b/test/testdata/same_level_file_test/golden.md
@@ -0,0 +1,22 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-first">first</a>, <a href="#my_rule-second">second</a>)
+</pre>
+
+This is my rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  first my_rule doc string   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+
+
diff --git a/test/testdata/same_level_file_test/input.bzl b/test/testdata/same_level_file_test/input.bzl
new file mode 100644
index 0000000..b1f67fb
--- /dev/null
+++ b/test/testdata/same_level_file_test/input.bzl
@@ -0,0 +1,15 @@
+# buildifier: disable=module-docstring
+load(":dep.bzl", "my_rule_impl")
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is my rule. It does stuff.",
+    attrs = {
+        "first": attr.label(
+            mandatory = True,
+            doc = "first my_rule doc string",
+            allow_single_file = True,
+        ),
+        "second": attr.string_dict(mandatory = True),
+    },
+)
diff --git a/test/testdata/simple_test/golden.md b/test/testdata/simple_test/golden.md
new file mode 100755
index 0000000..0a4276f
--- /dev/null
+++ b/test/testdata/simple_test/golden.md
@@ -0,0 +1,24 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule"></a>
+
+## my_rule
+
+<pre>
+my_rule(<a href="#my_rule-name">name</a>, <a href="#my_rule-first">first</a>, <a href="#my_rule-fourth">fourth</a>, <a href="#my_rule-second">second</a>, <a href="#my_rule-third">third</a>)
+</pre>
+
+This is my rule. It does stuff.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :-------------: | :-------------: | :-------------: | :-------------: | :-------------: |
+| name |  A unique name for this target.   | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required |  |
+| first |  first doc string   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+| fourth |  fourth doc string   | Boolean | optional | False |
+| second |  -   | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | required |  |
+| third |  -   | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | required |  |
+
+
diff --git a/test/testdata/simple_test/input.bzl b/test/testdata/simple_test/input.bzl
new file mode 100644
index 0000000..fe0ffc7
--- /dev/null
+++ b/test/testdata/simple_test/input.bzl
@@ -0,0 +1,19 @@
+# buildifier: disable=module-docstring
+def my_rule_impl(ctx):
+    return []
+
+my_rule = rule(
+    implementation = my_rule_impl,
+    doc = "This is my rule. It does stuff.",
+    attrs = {
+        "first": attr.label(
+            mandatory = True,
+            doc = "first doc string",
+            allow_single_file = True,
+        ),
+        "second": attr.string_dict(mandatory = True),
+        "third": attr.output(mandatory = True),
+        "fourth": attr.bool(default = False, doc = "fourth doc string", mandatory = False),
+        "_hidden": attr.string(),
+    },
+)
diff --git a/test/testdata/struct_default_value_test/golden.md b/test/testdata/struct_default_value_test/golden.md
new file mode 100755
index 0000000..6b15c1d
--- /dev/null
+++ b/test/testdata/struct_default_value_test/golden.md
@@ -0,0 +1,25 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#check_struct_default_values"></a>
+
+## check_struct_default_values
+
+<pre>
+check_struct_default_values(<a href="#check_struct_default_values-struct_no_args">struct_no_args</a>, <a href="#check_struct_default_values-struct_arg">struct_arg</a>, <a href="#check_struct_default_values-struct_args">struct_args</a>, <a href="#check_struct_default_values-struct_int_args">struct_int_args</a>,
+                            <a href="#check_struct_default_values-struct_struct_args">struct_struct_args</a>)
+</pre>
+
+Checks the default values of structs.
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| struct_no_args |  struct with no arguments   |  <code>struct()</code> |
+| struct_arg |  struct with one argument   |  <code>struct(foo = "bar")</code> |
+| struct_args |  struct with multiple arguments   |  <code>struct(bar = "foo", foo = "bar")</code> |
+| struct_int_args |  struct with int arguments   |  <code>struct(one = 1, three = 3, two = 2)</code> |
+| struct_struct_args |  struct with struct arguments   |  <code>struct(multiple = struct(one = 1, three = 3, two = 2), none = struct(), one = struct(foo = "bar"))</code> |
+
+
diff --git a/test/testdata/struct_default_value_test/input.bzl b/test/testdata/struct_default_value_test/input.bzl
new file mode 100644
index 0000000..ead514b
--- /dev/null
+++ b/test/testdata/struct_default_value_test/input.bzl
@@ -0,0 +1,22 @@
+"""The input file for struct default values test"""
+
+def check_struct_default_values(
+        struct_no_args = struct(),
+        struct_arg = struct(foo = "bar"),
+        struct_args = struct(foo = "bar", bar = "foo"),
+        struct_int_args = struct(one = 1, two = 2, three = 3),
+        struct_struct_args = struct(
+            none = struct(),
+            one = struct(foo = "bar"),
+            multiple = struct(one = 1, two = 2, three = 3),
+        )):
+    """Checks the default values of structs.
+
+    Args:
+        struct_no_args: struct with no arguments
+        struct_arg: struct with one argument
+        struct_args: struct with multiple arguments
+        struct_int_args: struct with int arguments
+        struct_struct_args: struct with struct arguments
+    """
+    pass
diff --git a/test/testdata/unknown_name_test/golden.md b/test/testdata/unknown_name_test/golden.md
new file mode 100755
index 0000000..71aba0c
--- /dev/null
+++ b/test/testdata/unknown_name_test/golden.md
@@ -0,0 +1,20 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+<a name="#my_rule_impl"></a>
+
+## my_rule_impl
+
+<pre>
+my_rule_impl(<a href="#my_rule_impl-ctx">ctx</a>)
+</pre>
+
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :-------------: | :-------------: | :-------------: |
+| ctx |  <p align="center"> - </p>   |  none |
+
+
diff --git a/test/testdata/unknown_name_test/input.bzl b/test/testdata/unknown_name_test/input.bzl
new file mode 100644
index 0000000..062f49d
--- /dev/null
+++ b/test/testdata/unknown_name_test/input.bzl
@@ -0,0 +1,13 @@
+# buildifier: disable=module-docstring
+def my_rule_impl(ctx):
+    return []
+
+rule(
+    implementation = my_rule_impl,
+    attrs = {
+        "first": attr.label(mandatory = True, allow_single_file = True),
+        "second": attr.string_dict(mandatory = True),
+        "third": attr.output(mandatory = True),
+        "fourth": attr.bool(default = False, mandatory = False),
+    },
+)
diff --git a/update-release-binary.sh b/update-release-binary.sh
new file mode 100755
index 0000000..b485afd
--- /dev/null
+++ b/update-release-binary.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Renerates the Stardoc release binary from source in @io_bazel.
+#
+# This should only need to be run for cutting a new Stardoc release.
+
+set -eu
+
+echo "** Building Stardoc from source..."
+bazel build @io_bazel//src/main/java/com/google/devtools/build/skydoc:skydoc_deploy.jar
+
+echo "** Copying Stardoc binary..."
+cp bazel-bin/external/io_bazel/src/main/java/com/google/devtools/build/skydoc/skydoc_deploy.jar \
+    stardoc/stardoc_binary.jar
+
+echo "** Stardoc copied."
+
+echo "** Building Renderer from source..."
+bazel build @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."
diff --git a/update-stardoc-docs.sh b/update-stardoc-docs.sh
new file mode 100755
index 0000000..986f5c2
--- /dev/null
+++ b/update-stardoc-docs.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Renerates the Stardoc rule documentation from source in @io_bazel.
+#
+# This should only need to be run for cutting a new Stardoc release.
+
+set -eu
+
+echo "** Generating Stardoc documentation..."
+bazel build //stardoc:stardoc_doc.md
+
+echo "** Copying result to docs/stardoc_rule.md ..."
+cp bazel-bin/stardoc/stardoc_doc.md docs/stardoc_rule.md
+
+echo "** Done! Please manually verify the new documentation looks good before committing."
+
diff --git a/update-stardoc-tests.sh b/update-stardoc-tests.sh
new file mode 100755
index 0000000..b01e39c
--- /dev/null
+++ b/update-stardoc-tests.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+# 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.
+#
+# Renerates most Stardoc golden files for Stardoc golden tests.
+#
+# When run, every golden file which is changed as a result of this script should
+# be manually examined and *heavily* scrutinized, as this usually indicates a large
+# in-place change of core rendering functionality of Stardoc.
+
+set -eu
+
+# Some tests cannot be automatically regenerated using this script, as they don't fall under the normal
+# golden test pattern
+EXCLUDED_TESTS="namespace_test_with_whitelist|proto_format_test|multi_level_namespace_test_with_whitelist|local_repository_test"
+echo "** Querying for tests..."
+regen_targets=$(bazel query //test:all | grep regenerate_with_jar | grep -vE "$EXCLUDED_TESTS")
+
+echo "** Building goldens..."
+bazel build $regen_targets
+
+echo "** Copying goldens..."
+for regen_target in $regen_targets; do
+  base_target_name=$(echo $regen_target | sed 's/\/\/test://g')
+  testdata_pkg_name=$(echo $base_target_name | sed 's/regenerate_with_jar_//g' | sed 's/_golden//g')
+  out_file="bazel-bin/test/${base_target_name}.out"
+  cp $out_file "test/testdata/${testdata_pkg_name}/golden.md"
+done
+
+echo "** Files copied."
+echo "Please note that not all golden files are correctly copied by this script."
+echo "You may want to manually run:"
+echo ""
+echo "bazel test //test:all"
+echo ""
+echo "...and manually update tests which are still broken."