Render *args / * / **kwargs properly in function summary line (#231)

Note that this requires Bazel 8 for an updated proto output from `starlark_doc_extract`.

Fixes #225
diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
index 19a8766..c3ef4e5 100644
--- a/.bazelci/presubmit.yml
+++ b/.bazelci/presubmit.yml
@@ -98,5 +98,15 @@
     test_flags: *common_flags
     test_targets:
     - "//test:proto_format_test_e2e_test"
+    - "//test:macro_kwargs_legacy_test_e2e_test"
+
+  bazel_8_tests:
+    name: Stardoc golden tests requiring Bazel HEAD
+    platform: ubuntu2004
+    bazel: last_green
+    build_flags: *common_flags
+    test_flags: *common_flags
+    test_targets:
+    - "//test:macro_kwargs_test_e2e_test"
 
 buildifier: latest
diff --git a/docs/stardoc_rule.md b/docs/stardoc_rule.md
index 52658ea..9851880 100644
--- a/docs/stardoc_rule.md
+++ b/docs/stardoc_rule.md
@@ -7,10 +7,10 @@
 ## stardoc
 
 <pre>
-stardoc(<a href="#stardoc-name">name</a>, <a href="#stardoc-input">input</a>, <a href="#stardoc-out">out</a>, <a href="#stardoc-deps">deps</a>, <a href="#stardoc-format">format</a>, <a href="#stardoc-symbol_names">symbol_names</a>, <a href="#stardoc-renderer">renderer</a>, <a href="#stardoc-aspect_template">aspect_template</a>, <a href="#stardoc-func_template">func_template</a>,
+stardoc(*, <a href="#stardoc-name">name</a>, <a href="#stardoc-input">input</a>, <a href="#stardoc-out">out</a>, <a href="#stardoc-deps">deps</a>, <a href="#stardoc-format">format</a>, <a href="#stardoc-symbol_names">symbol_names</a>, <a href="#stardoc-renderer">renderer</a>, <a href="#stardoc-aspect_template">aspect_template</a>, <a href="#stardoc-func_template">func_template</a>,
         <a href="#stardoc-header_template">header_template</a>, <a href="#stardoc-table_of_contents_template">table_of_contents_template</a>, <a href="#stardoc-provider_template">provider_template</a>, <a href="#stardoc-rule_template">rule_template</a>,
         <a href="#stardoc-repository_rule_template">repository_rule_template</a>, <a href="#stardoc-module_extension_template">module_extension_template</a>, <a href="#stardoc-footer_template">footer_template</a>, <a href="#stardoc-render_main_repo_name">render_main_repo_name</a>,
-        <a href="#stardoc-stamp">stamp</a>, <a href="#stardoc-kwargs">kwargs</a>)
+        <a href="#stardoc-stamp">stamp</a>, <a href="#stardoc-kwargs">**kwargs</a>)
 </pre>
 
 Generates documentation for exported starlark rule definitions in a target starlark file.
diff --git a/src/main/java/com/google/devtools/build/stardoc/rendering/MarkdownUtil.java b/src/main/java/com/google/devtools/build/stardoc/rendering/MarkdownUtil.java
index 4ac54ce..9324bb6 100644
--- a/src/main/java/com/google/devtools/build/stardoc/rendering/MarkdownUtil.java
+++ b/src/main/java/com/google/devtools/build/stardoc/rendering/MarkdownUtil.java
@@ -16,6 +16,9 @@
 
 import static com.google.common.base.Strings.isNullOrEmpty;
 import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.devtools.build.lib.starlarkdocextract.StardocOutputProtos.FunctionParamRole.PARAM_ROLE_KEYWORD_ONLY;
+import static com.google.devtools.build.lib.starlarkdocextract.StardocOutputProtos.FunctionParamRole.PARAM_ROLE_KWARGS;
+import static com.google.devtools.build.lib.starlarkdocextract.StardocOutputProtos.FunctionParamRole.PARAM_ROLE_VARARGS;
 import static java.util.Comparator.naturalOrder;
 import static java.util.stream.Collectors.joining;
 
@@ -38,6 +41,7 @@
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -247,9 +251,7 @@
       String providerName, ProviderInfo providerInfo, String paramAnchorPrefix) {
     ImmutableList<Param> params =
         providerInfo.hasInit()
-            ? providerInfo.getInit().getParameterList().stream()
-                .map(paramInfo -> new Param(paramInfo, paramAnchorPrefix))
-                .collect(toImmutableList())
+            ? getFunctionParamsInDeclarationOrder(providerInfo.getInit(), paramAnchorPrefix)
             : providerInfo.getFieldInfoList().stream()
                 .map(fieldInfo -> new Param(fieldInfo, paramAnchorPrefix))
                 .collect(toImmutableList());
@@ -324,11 +326,9 @@
    */
   @SuppressWarnings("unused") // Used by markdown template.
   public String funcSummary(StarlarkFunctionInfo funcInfo) {
-    ImmutableList<Param> params =
-        funcInfo.getParameterList().stream()
-            .map(paramInfo -> new Param(paramInfo, funcInfo.getFunctionName()))
-            .collect(toImmutableList());
-    return summary(funcInfo.getFunctionName(), params);
+    return summary(
+        funcInfo.getFunctionName(),
+        getFunctionParamsInDeclarationOrder(funcInfo, funcInfo.getFunctionName()));
   }
 
   /**
@@ -350,15 +350,30 @@
 
   /** Representation of a callable's parameter in a summary line. */
   private static final class Param {
-    // Parameter name for use in summary line
+    // User-visible name, including the leading "*" or "**" for residuals
     final String name;
     // HTML anchor for the parameter's detailed documentation elsewhere on the page
-    final String anchorName;
+    final Optional<String> anchorName;
+
+    public static final Param STAR_SEPARATOR = new Param("*", Optional.empty());
+
+    private Param(String name, Optional<String> anchorName) {
+      this.name = name;
+      this.anchorName = anchorName;
+    }
 
     Param(FunctionParamInfo paramInfo, String anchorPrefix) {
-      // TODO(https://github.com/bazelbuild/stardoc/issues/225): prepend "*" or "**" to this.name
-      // for residual params.
-      this.name = paramInfo.getName();
+      switch (paramInfo.getRole()) {
+        case PARAM_ROLE_VARARGS:
+          this.name = "*" + paramInfo.getName();
+          break;
+        case PARAM_ROLE_KWARGS:
+          this.name = "**" + paramInfo.getName();
+          break;
+        default:
+          this.name = paramInfo.getName();
+          break;
+      }
       this.anchorName = formatAnchorName(paramInfo.getName(), anchorPrefix);
     }
 
@@ -372,8 +387,8 @@
       this.anchorName = formatAnchorName(fieldInfo.getName(), anchorPrefix);
     }
 
-    private static String formatAnchorName(String name, String anchorPrefix) {
-      return String.format("%s-%s", anchorPrefix, name);
+    private static Optional<String> formatAnchorName(String name, String anchorPrefix) {
+      return Optional.of(String.format("%s-%s", anchorPrefix, name));
     }
 
     String getName() {
@@ -381,10 +396,58 @@
     }
 
     String renderHtml() {
-      return String.format("<a href=\"#%s\">%s</a>", anchorName, name);
+      if (anchorName.isPresent()) {
+        return String.format("<a href=\"#%s\">%s</a>", anchorName.get(), name);
+      } else {
+        return name;
+      }
     }
   }
 
+  private static ImmutableList<Param> getFunctionParamsInDeclarationOrder(
+      StarlarkFunctionInfo funcInfo, String anchorPrefix) {
+    List<FunctionParamInfo> paramInfos = funcInfo.getParameterList();
+    int nparams = paramInfos.size();
+    Optional<Param> kwargs;
+    if (nparams > 0 && paramInfos.get(nparams - 1).getRole() == PARAM_ROLE_KWARGS) {
+      kwargs = Optional.of(new Param(paramInfos.get(nparams - 1), anchorPrefix));
+      nparams--;
+    } else {
+      kwargs = Optional.empty();
+    }
+    Optional<Param> varargs;
+    if (nparams > 0 && paramInfos.get(nparams - 1).getRole() == PARAM_ROLE_VARARGS) {
+      varargs = Optional.of(new Param(paramInfos.get(nparams - 1), anchorPrefix));
+      nparams--;
+    } else {
+      varargs = Optional.empty();
+    }
+    // Invariant: nparams is now the number of non-residual parameters.
+
+    ImmutableList.Builder<Param> paramsBuilder = new ImmutableList.Builder();
+    int numKwonly = 0;
+    // Add ordinary or positional-only params
+    for (int i = 0; i < nparams; i++) {
+      FunctionParamInfo paramInfo = paramInfos.get(i);
+      if (paramInfo.getRole() == PARAM_ROLE_KEYWORD_ONLY) {
+        numKwonly = nparams - i;
+        break;
+      }
+      paramsBuilder.add(new Param(paramInfo, anchorPrefix));
+    }
+    // Add *args or (if needed) the "*" separator
+    if (varargs.isPresent() || numKwonly > 0) {
+      paramsBuilder.add(varargs.orElse(Param.STAR_SEPARATOR));
+    }
+    // Add kwonly params (if any)
+    for (int i = nparams - numKwonly; i < nparams; i++) {
+      paramsBuilder.add(new Param(paramInfos.get(i), anchorPrefix));
+    }
+    // Add **kwargs
+    kwargs.ifPresent(paramsBuilder::add);
+    return paramsBuilder.build();
+  }
+
   /**
    * Wraps the given function parameter names to be able to construct a function summary that stays
    * within the provided line length limit.
diff --git a/stardoc/proto/stardoc_output.proto b/stardoc/proto/stardoc_output.proto
index 82c97e8..ee6082f 100644
--- a/stardoc/proto/stardoc_output.proto
+++ b/stardoc/proto/stardoc_output.proto
@@ -13,7 +13,8 @@
 // limitations under the License.
 //
 // Vendored from src/main/protobuf/stardoc_output.proto
-// in the Bazel source tree at commit f4cfc846dbdf5f6c19d0a716fccd2ddcdae0d609n
+// in the Bazel source tree at commit bd1c3af2ea14e81268e940d2b8ba5ad00c3f08d7n
+
 //
 // Protos for Stardoc data.
 //
@@ -193,7 +194,16 @@
   // "foo.frobnicate".
   string function_name = 1;
 
-  // The parameters for the function.
+  // The parameters for the function, in the following order:
+  // - positional parameters
+  // - keyword-only parameters
+  // - residual varargs parameter (`*args`)
+  // - residual keyword arguments parameter (`**kwargs`)
+  // This order differs from the order in which parameters are listed in the
+  // function's declaration (where positional parameters and keyword-only
+  // parameters are separated either by `*` or `*args`). The declaration order
+  // can be recovered by looking for the transition from ordinary/positional to
+  // keyword-only.
   repeated FunctionParamInfo parameter = 2;
 
   // The documented description of the function (if specified in the function's
@@ -213,9 +223,28 @@
   OriginKey origin_key = 6;
 }
 
+// Representation of the syntactic role of a given function parameter.
+enum FunctionParamRole {
+  PARAM_ROLE_UNSPECIFIED = 0;
+  // An ordinary parameter which may be used as a positional or by keyword.
+  PARAM_ROLE_ORDINARY = 1;
+  // A positional-only parameter; such parameters cannot be defined in pure
+  // Starlark code, but exist in some natively-defined functions.
+  PARAM_ROLE_POSITIONAL_ONLY = 2;
+  // A keyword-only parameter, i.e. a non-vararg/kwarg parameter that follows
+  // `*` or `*args` in the function's declaration.
+  PARAM_ROLE_KEYWORD_ONLY = 3;
+  // Residual varargs, typically `*args` in the function's declaration.
+  PARAM_ROLE_VARARGS = 4;
+  // Residual keyword arguments, typically `**kwargs` in the function's
+  // declaration.
+  PARAM_ROLE_KWARGS = 5;
+}
+
 // Representation of a Starlark function parameter definition.
 message FunctionParamInfo {
-  // The name of the parameter.
+  // The name of the parameter. This does *not* include the `*` or `**` prefix
+  // for varargs or residual keyword argument parameters.
   string name = 1;
 
   // The documented description of the parameter (if specified in the function's
@@ -230,6 +259,9 @@
   // parameter. This might be false even if defaultValue is empty in the case of
   // special parameter such as *args and **kwargs"
   bool mandatory = 4;
+
+  // The parameter's syntactic role.
+  FunctionParamRole role = 5;
 }
 
 message FunctionReturnInfo {
diff --git a/test/BUILD b/test/BUILD
index 4e8e8f2..3c5bc9e 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -13,6 +13,11 @@
     name = "stardoc_self_gen_test",
     golden_file = "//stardoc:stardoc_doc.md",
     stardoc_doc = "//:stardoc_rule_doc",
+    # stardoc_doc.md output was generated with Bazel HEAD on 2024-06-12 and may differ in other versions
+    tags = [
+        "bazel_8",
+        "manual",
+    ],
 )
 
 exports_files(["testdata/fakedeps/dep.bzl"])
@@ -200,9 +205,25 @@
 )
 
 stardoc_test(
+    name = "macro_kwargs_legacy_test",
+    golden_file = "testdata/macro_kwargs_test/legacy_golden.md",
+    input_file = "testdata/macro_kwargs_test/input.bzl",
+    # Golden output was generated with Bazel 7.1 and may differ in other versions
+    tags = [
+        "bazel_7_1",
+        "manual",
+    ],
+)
+
+stardoc_test(
     name = "macro_kwargs_test",
     golden_file = "testdata/macro_kwargs_test/golden.md",
     input_file = "testdata/macro_kwargs_test/input.bzl",
+    # Golden output was generated with Bazel HEAD on 2024-06-12 and may differ in other versions
+    tags = [
+        "bazel_8",
+        "manual",
+    ],
 )
 
 stardoc_test(
diff --git a/test/testdata/macro_kwargs_test/golden.md b/test/testdata/macro_kwargs_test/golden.md
index 1a9df5b..c4e95cd 100644
--- a/test/testdata/macro_kwargs_test/golden.md
+++ b/test/testdata/macro_kwargs_test/golden.md
@@ -7,7 +7,7 @@
 ## macro_with_args
 
 <pre>
-macro_with_args(<a href="#macro_with_args-name">name</a>, <a href="#macro_with_args-args">args</a>)
+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.
@@ -25,12 +25,92 @@
 An empty list.
 
 
+<a id="macro_with_args_and_kwonly"></a>
+
+## macro_with_args_and_kwonly
+
+<pre>
+macro_with_args_and_kwonly(<a href="#macro_with_args_and_kwonly-args">*args</a>, <a href="#macro_with_args_and_kwonly-name">name</a>)
+</pre>
+
+*args and a keyword-only param
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_args_and_kwonly-name"></a>name |  The name   |  none |
+| <a id="macro_with_args_and_kwonly-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_args_and_kwonlys"></a>
+
+## macro_with_args_and_kwonlys
+
+<pre>
+macro_with_args_and_kwonlys(<a href="#macro_with_args_and_kwonlys-args">*args</a>, <a href="#macro_with_args_and_kwonlys-name">name</a>, <a href="#macro_with_args_and_kwonlys-number">number</a>)
+</pre>
+
+*args and several keyword-only params
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_args_and_kwonlys-name"></a>name |  The name   |  none |
+| <a id="macro_with_args_and_kwonlys-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_args_and_kwonlys-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_args_kwonly_and_kwargs"></a>
+
+## macro_with_args_kwonly_and_kwargs
+
+<pre>
+macro_with_args_kwonly_and_kwargs(<a href="#macro_with_args_kwonly_and_kwargs-args">*args</a>, <a href="#macro_with_args_kwonly_and_kwargs-name">name</a>, <a href="#macro_with_args_kwonly_and_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+*args, a keyword-only param, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_args_kwonly_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_args_kwonly_and_kwargs-args"></a>args |  Positional arguments   |  none |
+| <a id="macro_with_args_kwonly_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_args_kwonlys_and_kwargs"></a>
+
+## macro_with_args_kwonlys_and_kwargs
+
+<pre>
+macro_with_args_kwonlys_and_kwargs(<a href="#macro_with_args_kwonlys_and_kwargs-args">*args</a>, <a href="#macro_with_args_kwonlys_and_kwargs-name">name</a>, <a href="#macro_with_args_kwonlys_and_kwargs-number">number</a>, <a href="#macro_with_args_kwonlys_and_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+*args, several keyword-only params, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_args_kwonlys_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_args_kwonlys_and_kwargs-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_args_kwonlys_and_kwargs-args"></a>args |  Positional arguments   |  none |
+| <a id="macro_with_args_kwonlys_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
 <a id="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>)
+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.
@@ -58,7 +138,7 @@
 ## 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>)
+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.
@@ -85,3 +165,302 @@
 An empty list.
 
 
+<a id="macro_with_kwonly"></a>
+
+## macro_with_kwonly
+
+<pre>
+macro_with_kwonly(*, <a href="#macro_with_kwonly-name">name</a>)
+</pre>
+
+One keyword-only param
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_kwonly-name"></a>name |  The name   |  none |
+
+
+<a id="macro_with_kwonly_and_kwargs"></a>
+
+## macro_with_kwonly_and_kwargs
+
+<pre>
+macro_with_kwonly_and_kwargs(*, <a href="#macro_with_kwonly_and_kwargs-name">name</a>, <a href="#macro_with_kwonly_and_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+One keyword-only param and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_kwonly_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_kwonly_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_kwonlys"></a>
+
+## macro_with_kwonlys
+
+<pre>
+macro_with_kwonlys(*, <a href="#macro_with_kwonlys-name">name</a>, <a href="#macro_with_kwonlys-number">number</a>)
+</pre>
+
+Several keyword-only params
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_kwonlys-name"></a>name |  The name   |  none |
+| <a id="macro_with_kwonlys-number"></a>number |  The number   |  `3` |
+
+
+<a id="macro_with_kwonlys_and_kwargs"></a>
+
+## macro_with_kwonlys_and_kwargs
+
+<pre>
+macro_with_kwonlys_and_kwargs(*, <a href="#macro_with_kwonlys_and_kwargs-name">name</a>, <a href="#macro_with_kwonlys_and_kwargs-number">number</a>, <a href="#macro_with_kwonlys_and_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+Several keyword-only params and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_kwonlys_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_kwonlys_and_kwargs-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_kwonlys_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_only_args"></a>
+
+## macro_with_only_args
+
+<pre>
+macro_with_only_args(<a href="#macro_with_only_args-args">*args</a>)
+</pre>
+
+Macro only taking *args
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_only_args-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_only_args_and_kwargs"></a>
+
+## macro_with_only_args_and_kwargs
+
+<pre>
+macro_with_only_args_and_kwargs(<a href="#macro_with_only_args_and_kwargs-args">*args</a>, <a href="#macro_with_only_args_and_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+Macro only taking *args and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_only_args_and_kwargs-args"></a>args |  Positional arguments   |  none |
+| <a id="macro_with_only_args_and_kwargs-kwargs"></a>kwargs |  Named arguments   |  none |
+
+
+<a id="macro_with_only_kwargs"></a>
+
+## macro_with_only_kwargs
+
+<pre>
+macro_with_only_kwargs(<a href="#macro_with_only_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+Macro only taking **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_only_kwargs-kwargs"></a>kwargs |  Named arguments   |  none |
+
+
+<a id="macro_with_ordinary_param_and_kwonlys"></a>
+
+## macro_with_ordinary_param_and_kwonlys
+
+<pre>
+macro_with_ordinary_param_and_kwonlys(<a href="#macro_with_ordinary_param_and_kwonlys-name">name</a>, *, <a href="#macro_with_ordinary_param_and_kwonlys-number">number</a>, <a href="#macro_with_ordinary_param_and_kwonlys-config">config</a>)
+</pre>
+
+One ordinary param and several keyword-only params
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_param_and_kwonlys-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_param_and_kwonlys-number"></a>number |  The number   |  none |
+| <a id="macro_with_ordinary_param_and_kwonlys-config"></a>config |  Configuration   |  none |
+
+
+<a id="macro_with_ordinary_param_args_and_kwonlys"></a>
+
+## macro_with_ordinary_param_args_and_kwonlys
+
+<pre>
+macro_with_ordinary_param_args_and_kwonlys(<a href="#macro_with_ordinary_param_args_and_kwonlys-name">name</a>, <a href="#macro_with_ordinary_param_args_and_kwonlys-args">*args</a>, <a href="#macro_with_ordinary_param_args_and_kwonlys-number">number</a>, <a href="#macro_with_ordinary_param_args_and_kwonlys-config">config</a>)
+</pre>
+
+One ordinary param, *args, and several keyword-only params
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_param_args_and_kwonlys-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_param_args_and_kwonlys-number"></a>number |  The number   |  none |
+| <a id="macro_with_ordinary_param_args_and_kwonlys-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_param_args_and_kwonlys-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_ordinary_param_args_kwonlys_and_kwargs"></a>
+
+## macro_with_ordinary_param_args_kwonlys_and_kwargs
+
+<pre>
+macro_with_ordinary_param_args_kwonlys_and_kwargs(<a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-name">name</a>, <a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-args">*args</a>, <a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-number">number</a>, <a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-config">config</a>, <a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+One ordinary param, *args, several keyword-only params, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-number"></a>number |  The number   |  none |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-args"></a>args |  Other positional arguments   |  none |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_ordinary_param_kwonlys_and_kwargs"></a>
+
+## macro_with_ordinary_param_kwonlys_and_kwargs
+
+<pre>
+macro_with_ordinary_param_kwonlys_and_kwargs(<a href="#macro_with_ordinary_param_kwonlys_and_kwargs-name">name</a>, *, <a href="#macro_with_ordinary_param_kwonlys_and_kwargs-number">number</a>, <a href="#macro_with_ordinary_param_kwonlys_and_kwargs-config">config</a>, <a href="#macro_with_ordinary_param_kwonlys_and_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+One ordinary param, several keyword-only params, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_param_kwonlys_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_param_kwonlys_and_kwargs-number"></a>number |  The number   |  none |
+| <a id="macro_with_ordinary_param_kwonlys_and_kwargs-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_param_kwonlys_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_ordinary_params_and_kwonly"></a>
+
+## macro_with_ordinary_params_and_kwonly
+
+<pre>
+macro_with_ordinary_params_and_kwonly(<a href="#macro_with_ordinary_params_and_kwonly-name">name</a>, <a href="#macro_with_ordinary_params_and_kwonly-number">number</a>, *, <a href="#macro_with_ordinary_params_and_kwonly-config">config</a>)
+</pre>
+
+Several ordinary params and a keyword-only param
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_params_and_kwonly-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_params_and_kwonly-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_ordinary_params_and_kwonly-config"></a>config |  Configuration   |  none |
+
+
+<a id="macro_with_ordinary_params_args_and_kwonly"></a>
+
+## macro_with_ordinary_params_args_and_kwonly
+
+<pre>
+macro_with_ordinary_params_args_and_kwonly(<a href="#macro_with_ordinary_params_args_and_kwonly-name">name</a>, <a href="#macro_with_ordinary_params_args_and_kwonly-number">number</a>, <a href="#macro_with_ordinary_params_args_and_kwonly-args">*args</a>, <a href="#macro_with_ordinary_params_args_and_kwonly-config">config</a>)
+</pre>
+
+Several ordinary params, *args, and a keyword-only param
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_params_args_and_kwonly-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_params_args_and_kwonly-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_ordinary_params_args_and_kwonly-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_params_args_and_kwonly-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_ordinary_params_args_kwonly_and_kwargs"></a>
+
+## macro_with_ordinary_params_args_kwonly_and_kwargs
+
+<pre>
+macro_with_ordinary_params_args_kwonly_and_kwargs(<a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-name">name</a>, <a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-number">number</a>, <a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-args">*args</a>, <a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-config">config</a>, <a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+Several ordinary params, *args, one keyword-only param, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-args"></a>args |  Other positional arguments   |  none |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_ordinary_params_kwonly_and_kwargs"></a>
+
+## macro_with_ordinary_params_kwonly_and_kwargs
+
+<pre>
+macro_with_ordinary_params_kwonly_and_kwargs(<a href="#macro_with_ordinary_params_kwonly_and_kwargs-name">name</a>, <a href="#macro_with_ordinary_params_kwonly_and_kwargs-number">number</a>, *, <a href="#macro_with_ordinary_params_kwonly_and_kwargs-config">config</a>, <a href="#macro_with_ordinary_params_kwonly_and_kwargs-kwargs">**kwargs</a>)
+</pre>
+
+Several ordinary params, a keyword-only param, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_params_kwonly_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_params_kwonly_and_kwargs-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_ordinary_params_kwonly_and_kwargs-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_params_kwonly_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
diff --git a/test/testdata/macro_kwargs_test/input.bzl b/test/testdata/macro_kwargs_test/input.bzl
index 8de782e..844899d 100644
--- a/test/testdata/macro_kwargs_test/input.bzl
+++ b/test/testdata/macro_kwargs_test/input.bzl
@@ -50,3 +50,211 @@
     """
     _ignore = [name, number, args, kwargs]  # @unused
     return []
+
+# buildifier: disable=unused-variable
+def macro_with_only_args(*args):
+    """Macro only taking *args
+
+    Args:
+      *args: Positional arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_only_kwargs(**kwargs):
+    """Macro only taking **kwargs
+
+    Args:
+      **kwargs: Named arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_only_args_and_kwargs(*args, **kwargs):
+    """Macro only taking *args and **kwargs
+
+    Args:
+      *args: Positional arguments
+      **kwargs: Named arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_kwonly(*, name):
+    """One keyword-only param
+
+    Args:
+      name: The name
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_kwonlys(*, name, number = 3):
+    """Several keyword-only params
+
+    Args:
+      name: The name
+      number: The number
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_kwonly_and_kwargs(*, name, **kwargs):
+    """One keyword-only param and **kwargs
+
+    Args:
+      name: The name
+      **kwargs: Other named arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_kwonlys_and_kwargs(*, name, number = 3, **kwargs):
+    """Several keyword-only params and **kwargs
+
+    Args:
+      name: The name
+      number: The number
+      **kwargs: Other named arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_ordinary_params_and_kwonly(name, number = 3, *, config):
+    """Several ordinary params and a keyword-only param
+
+    Args:
+      name: The name
+      number: The number
+      config: Configuration
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_ordinary_param_and_kwonlys(name, *, number, config):
+    """One ordinary param and several keyword-only params
+
+    Args:
+      name: The name
+      number: The number
+      config: Configuration
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_ordinary_param_kwonlys_and_kwargs(name, *, number, config, **kwargs):
+    """One ordinary param, several keyword-only params, and **kwargs
+
+    Args:
+      name: The name
+      number: The number
+      config: Configuration
+      **kwargs: Other named arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_ordinary_params_kwonly_and_kwargs(name, number = 3, *, config, **kwargs):
+    """Several ordinary params, a keyword-only param, and **kwargs
+
+    Args:
+      name: The name
+      number: The number
+      config: Configuration
+      **kwargs: Other named arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_args_and_kwonly(*args, name):
+    """*args and a keyword-only param
+
+    Args:
+      *args: Positional arguments
+      name: The name
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_args_and_kwonlys(*args, name, number = 3):
+    """*args and several keyword-only params
+
+    Args:
+      *args: Positional arguments
+      name: The name
+      number: The number
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_args_kwonly_and_kwargs(*args, name, **kwargs):
+    """*args, a keyword-only param, and **kwargs
+
+    Args:
+      *args: Positional arguments
+      name: The name
+      **kwargs: Other named arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_args_kwonlys_and_kwargs(*args, name, number = 3, **kwargs):
+    """*args, several keyword-only params, and **kwargs
+
+    Args:
+      *args: Positional arguments
+      name: The name
+      number: The number
+      **kwargs: Other named arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_ordinary_params_args_and_kwonly(name, number = 3, *args, config):
+    """Several ordinary params, *args, and a keyword-only param
+
+    Args:
+      name: The name
+      number: The number
+      *args: Positional arguments
+      config: Configuration
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_ordinary_param_args_and_kwonlys(name, *args, number, config):
+    """One ordinary param, *args, and several keyword-only params
+
+    Args:
+      name: The name
+      *args: Positional arguments
+      number: The number
+      config: Configuration
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_ordinary_param_args_kwonlys_and_kwargs(name, *args, number, config, **kwargs):
+    """One ordinary param, *args, several keyword-only params, and **kwargs
+
+    Args:
+      name: The name
+      *args: Other positional arguments
+      number: The number
+      config: Configuration
+      **kwargs: Other named arguments
+    """
+    pass
+
+# buildifier: disable=unused-variable
+def macro_with_ordinary_params_args_kwonly_and_kwargs(name, number = 3, *args, config, **kwargs):
+    """Several ordinary params, *args, one keyword-only param, and **kwargs
+
+    Args:
+      name: The name
+      number: The number
+      *args: Other positional arguments
+      config: Configuration
+      **kwargs: Other named arguments
+    """
+    pass
diff --git a/test/testdata/macro_kwargs_test/legacy_golden.md b/test/testdata/macro_kwargs_test/legacy_golden.md
new file mode 100644
index 0000000..0b1f040
--- /dev/null
+++ b/test/testdata/macro_kwargs_test/legacy_golden.md
@@ -0,0 +1,466 @@
+<!-- Generated with Stardoc: http://skydoc.bazel.build -->
+
+Tests for functions which use *args or **kwargs
+
+<a id="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 |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_args-name"></a>name |  The name of the test rule.   |  none |
+| <a id="macro_with_args-args"></a>args |  Other arguments to include   |  none |
+
+**RETURNS**
+
+An empty list.
+
+
+<a id="macro_with_args_and_kwonly"></a>
+
+## macro_with_args_and_kwonly
+
+<pre>
+macro_with_args_and_kwonly(<a href="#macro_with_args_and_kwonly-name">name</a>, <a href="#macro_with_args_and_kwonly-args">args</a>)
+</pre>
+
+*args and a keyword-only param
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_args_and_kwonly-name"></a>name |  The name   |  none |
+| <a id="macro_with_args_and_kwonly-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_args_and_kwonlys"></a>
+
+## macro_with_args_and_kwonlys
+
+<pre>
+macro_with_args_and_kwonlys(<a href="#macro_with_args_and_kwonlys-name">name</a>, <a href="#macro_with_args_and_kwonlys-number">number</a>, <a href="#macro_with_args_and_kwonlys-args">args</a>)
+</pre>
+
+*args and several keyword-only params
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_args_and_kwonlys-name"></a>name |  The name   |  none |
+| <a id="macro_with_args_and_kwonlys-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_args_and_kwonlys-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_args_kwonly_and_kwargs"></a>
+
+## macro_with_args_kwonly_and_kwargs
+
+<pre>
+macro_with_args_kwonly_and_kwargs(<a href="#macro_with_args_kwonly_and_kwargs-name">name</a>, <a href="#macro_with_args_kwonly_and_kwargs-args">args</a>, <a href="#macro_with_args_kwonly_and_kwargs-kwargs">kwargs</a>)
+</pre>
+
+*args, a keyword-only param, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_args_kwonly_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_args_kwonly_and_kwargs-args"></a>args |  Positional arguments   |  none |
+| <a id="macro_with_args_kwonly_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_args_kwonlys_and_kwargs"></a>
+
+## macro_with_args_kwonlys_and_kwargs
+
+<pre>
+macro_with_args_kwonlys_and_kwargs(<a href="#macro_with_args_kwonlys_and_kwargs-name">name</a>, <a href="#macro_with_args_kwonlys_and_kwargs-number">number</a>, <a href="#macro_with_args_kwonlys_and_kwargs-args">args</a>, <a href="#macro_with_args_kwonlys_and_kwargs-kwargs">kwargs</a>)
+</pre>
+
+*args, several keyword-only params, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_args_kwonlys_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_args_kwonlys_and_kwargs-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_args_kwonlys_and_kwargs-args"></a>args |  Positional arguments   |  none |
+| <a id="macro_with_args_kwonlys_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="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 |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_both-name"></a>name |  The name of the test rule.   |  none |
+| <a id="macro_with_both-number"></a>number |  Some number used for important things   |  `3` |
+| <a id="macro_with_both-args"></a>args |  Other arguments to include   |  none |
+| <a id="macro_with_both-kwargs"></a>kwargs |  Other attributes to include   |  none |
+
+**RETURNS**
+
+An empty list.
+
+
+<a id="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 |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_kwargs-name"></a>name |  The name of the test rule.   |  none |
+| <a id="macro_with_kwargs-config"></a>config |  Config to use for my macro   |  none |
+| <a id="macro_with_kwargs-deps"></a>deps |  List of my macro's dependencies   |  `[]` |
+| <a id="macro_with_kwargs-kwargs"></a>kwargs |  Other attributes to include   |  none |
+
+**RETURNS**
+
+An empty list.
+
+
+<a id="macro_with_kwonly"></a>
+
+## macro_with_kwonly
+
+<pre>
+macro_with_kwonly(<a href="#macro_with_kwonly-name">name</a>)
+</pre>
+
+One keyword-only param
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_kwonly-name"></a>name |  The name   |  none |
+
+
+<a id="macro_with_kwonly_and_kwargs"></a>
+
+## macro_with_kwonly_and_kwargs
+
+<pre>
+macro_with_kwonly_and_kwargs(<a href="#macro_with_kwonly_and_kwargs-name">name</a>, <a href="#macro_with_kwonly_and_kwargs-kwargs">kwargs</a>)
+</pre>
+
+One keyword-only param and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_kwonly_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_kwonly_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_kwonlys"></a>
+
+## macro_with_kwonlys
+
+<pre>
+macro_with_kwonlys(<a href="#macro_with_kwonlys-name">name</a>, <a href="#macro_with_kwonlys-number">number</a>)
+</pre>
+
+Several keyword-only params
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_kwonlys-name"></a>name |  The name   |  none |
+| <a id="macro_with_kwonlys-number"></a>number |  The number   |  `3` |
+
+
+<a id="macro_with_kwonlys_and_kwargs"></a>
+
+## macro_with_kwonlys_and_kwargs
+
+<pre>
+macro_with_kwonlys_and_kwargs(<a href="#macro_with_kwonlys_and_kwargs-name">name</a>, <a href="#macro_with_kwonlys_and_kwargs-number">number</a>, <a href="#macro_with_kwonlys_and_kwargs-kwargs">kwargs</a>)
+</pre>
+
+Several keyword-only params and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_kwonlys_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_kwonlys_and_kwargs-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_kwonlys_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_only_args"></a>
+
+## macro_with_only_args
+
+<pre>
+macro_with_only_args(<a href="#macro_with_only_args-args">args</a>)
+</pre>
+
+Macro only taking *args
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_only_args-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_only_args_and_kwargs"></a>
+
+## macro_with_only_args_and_kwargs
+
+<pre>
+macro_with_only_args_and_kwargs(<a href="#macro_with_only_args_and_kwargs-args">args</a>, <a href="#macro_with_only_args_and_kwargs-kwargs">kwargs</a>)
+</pre>
+
+Macro only taking *args and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_only_args_and_kwargs-args"></a>args |  Positional arguments   |  none |
+| <a id="macro_with_only_args_and_kwargs-kwargs"></a>kwargs |  Named arguments   |  none |
+
+
+<a id="macro_with_only_kwargs"></a>
+
+## macro_with_only_kwargs
+
+<pre>
+macro_with_only_kwargs(<a href="#macro_with_only_kwargs-kwargs">kwargs</a>)
+</pre>
+
+Macro only taking **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_only_kwargs-kwargs"></a>kwargs |  Named arguments   |  none |
+
+
+<a id="macro_with_ordinary_param_and_kwonlys"></a>
+
+## macro_with_ordinary_param_and_kwonlys
+
+<pre>
+macro_with_ordinary_param_and_kwonlys(<a href="#macro_with_ordinary_param_and_kwonlys-name">name</a>, <a href="#macro_with_ordinary_param_and_kwonlys-number">number</a>, <a href="#macro_with_ordinary_param_and_kwonlys-config">config</a>)
+</pre>
+
+One ordinary param and several keyword-only params
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_param_and_kwonlys-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_param_and_kwonlys-number"></a>number |  The number   |  none |
+| <a id="macro_with_ordinary_param_and_kwonlys-config"></a>config |  Configuration   |  none |
+
+
+<a id="macro_with_ordinary_param_args_and_kwonlys"></a>
+
+## macro_with_ordinary_param_args_and_kwonlys
+
+<pre>
+macro_with_ordinary_param_args_and_kwonlys(<a href="#macro_with_ordinary_param_args_and_kwonlys-name">name</a>, <a href="#macro_with_ordinary_param_args_and_kwonlys-number">number</a>, <a href="#macro_with_ordinary_param_args_and_kwonlys-config">config</a>, <a href="#macro_with_ordinary_param_args_and_kwonlys-args">args</a>)
+</pre>
+
+One ordinary param, *args, and several keyword-only params
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_param_args_and_kwonlys-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_param_args_and_kwonlys-number"></a>number |  The number   |  none |
+| <a id="macro_with_ordinary_param_args_and_kwonlys-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_param_args_and_kwonlys-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_ordinary_param_args_kwonlys_and_kwargs"></a>
+
+## macro_with_ordinary_param_args_kwonlys_and_kwargs
+
+<pre>
+macro_with_ordinary_param_args_kwonlys_and_kwargs(<a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-name">name</a>, <a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-number">number</a>, <a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-config">config</a>, <a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-args">args</a>, <a href="#macro_with_ordinary_param_args_kwonlys_and_kwargs-kwargs">kwargs</a>)
+</pre>
+
+One ordinary param, *args, several keyword-only params, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-number"></a>number |  The number   |  none |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-args"></a>args |  Other positional arguments   |  none |
+| <a id="macro_with_ordinary_param_args_kwonlys_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_ordinary_param_kwonlys_and_kwargs"></a>
+
+## macro_with_ordinary_param_kwonlys_and_kwargs
+
+<pre>
+macro_with_ordinary_param_kwonlys_and_kwargs(<a href="#macro_with_ordinary_param_kwonlys_and_kwargs-name">name</a>, <a href="#macro_with_ordinary_param_kwonlys_and_kwargs-number">number</a>, <a href="#macro_with_ordinary_param_kwonlys_and_kwargs-config">config</a>, <a href="#macro_with_ordinary_param_kwonlys_and_kwargs-kwargs">kwargs</a>)
+</pre>
+
+One ordinary param, several keyword-only params, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_param_kwonlys_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_param_kwonlys_and_kwargs-number"></a>number |  The number   |  none |
+| <a id="macro_with_ordinary_param_kwonlys_and_kwargs-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_param_kwonlys_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_ordinary_params_and_kwonly"></a>
+
+## macro_with_ordinary_params_and_kwonly
+
+<pre>
+macro_with_ordinary_params_and_kwonly(<a href="#macro_with_ordinary_params_and_kwonly-name">name</a>, <a href="#macro_with_ordinary_params_and_kwonly-number">number</a>, <a href="#macro_with_ordinary_params_and_kwonly-config">config</a>)
+</pre>
+
+Several ordinary params and a keyword-only param
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_params_and_kwonly-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_params_and_kwonly-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_ordinary_params_and_kwonly-config"></a>config |  Configuration   |  none |
+
+
+<a id="macro_with_ordinary_params_args_and_kwonly"></a>
+
+## macro_with_ordinary_params_args_and_kwonly
+
+<pre>
+macro_with_ordinary_params_args_and_kwonly(<a href="#macro_with_ordinary_params_args_and_kwonly-name">name</a>, <a href="#macro_with_ordinary_params_args_and_kwonly-number">number</a>, <a href="#macro_with_ordinary_params_args_and_kwonly-config">config</a>, <a href="#macro_with_ordinary_params_args_and_kwonly-args">args</a>)
+</pre>
+
+Several ordinary params, *args, and a keyword-only param
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_params_args_and_kwonly-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_params_args_and_kwonly-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_ordinary_params_args_and_kwonly-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_params_args_and_kwonly-args"></a>args |  Positional arguments   |  none |
+
+
+<a id="macro_with_ordinary_params_args_kwonly_and_kwargs"></a>
+
+## macro_with_ordinary_params_args_kwonly_and_kwargs
+
+<pre>
+macro_with_ordinary_params_args_kwonly_and_kwargs(<a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-name">name</a>, <a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-number">number</a>, <a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-config">config</a>, <a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-args">args</a>, <a href="#macro_with_ordinary_params_args_kwonly_and_kwargs-kwargs">kwargs</a>)
+</pre>
+
+Several ordinary params, *args, one keyword-only param, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-args"></a>args |  Other positional arguments   |  none |
+| <a id="macro_with_ordinary_params_args_kwonly_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
+<a id="macro_with_ordinary_params_kwonly_and_kwargs"></a>
+
+## macro_with_ordinary_params_kwonly_and_kwargs
+
+<pre>
+macro_with_ordinary_params_kwonly_and_kwargs(<a href="#macro_with_ordinary_params_kwonly_and_kwargs-name">name</a>, <a href="#macro_with_ordinary_params_kwonly_and_kwargs-number">number</a>, <a href="#macro_with_ordinary_params_kwonly_and_kwargs-config">config</a>, <a href="#macro_with_ordinary_params_kwonly_and_kwargs-kwargs">kwargs</a>)
+</pre>
+
+Several ordinary params, a keyword-only param, and **kwargs
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="macro_with_ordinary_params_kwonly_and_kwargs-name"></a>name |  The name   |  none |
+| <a id="macro_with_ordinary_params_kwonly_and_kwargs-number"></a>number |  The number   |  `3` |
+| <a id="macro_with_ordinary_params_kwonly_and_kwargs-config"></a>config |  Configuration   |  none |
+| <a id="macro_with_ordinary_params_kwonly_and_kwargs-kwargs"></a>kwargs |  Other named arguments   |  none |
+
+
diff --git a/update-stardoc-tests.sh b/update-stardoc-tests.sh
index dca9b18..c79f50b 100755
--- a/update-stardoc-tests.sh
+++ b/update-stardoc-tests.sh
@@ -37,7 +37,7 @@
 
 # Some tests cannot be automatically regenerated using this script, as they don't fall under the normal
 # golden test pattern or require a specific Bazel version
-EXCLUDED_TESTS="namespace_test_with_allowlist|multi_level_namespace_test_with_allowlist|local_repository_test|stamping_with_stamping_off"
+EXCLUDED_TESTS="namespace_test_with_allowlist|multi_level_namespace_test_with_allowlist|local_repository_test|stamping_with_stamping_off|macro_kwargs"
 echo "** Querying for tests..."
 regen_targets=$(${BAZEL} query //test:all | grep regenerate_ | grep -vE "_golden\.extract|$EXCLUDED_TESTS")