Skip to content

Commit

Permalink
Add helper for Markdown inline code escaping
Browse files Browse the repository at this point in the history
The helper adds escaping to a string so that it can be embedded in a Markdown inline code segment delimited by backticks.

Closes #18867.

PiperOrigin-RevId: 547527057
Change-Id: Ie37d076c46f82ddd04e31c33c0f695109c5d29f5
  • Loading branch information
fmeum authored and copybara-github committed Jul 12, 2023
1 parent 928d924 commit 3d26048
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package com.google.devtools.build.skydoc.rendering;

import static java.util.Comparator.naturalOrder;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.AspectInfo;
Expand All @@ -26,11 +28,10 @@
import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.StarlarkFunctionInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
* Contains a number of utility methods for markdown rendering.
*/
/** Contains a number of utility methods for markdown rendering. */
public final class MarkdownUtil {
private static final int MAX_LINE_LENGTH = 100;

Expand Down Expand Up @@ -84,6 +85,34 @@ public String htmlEscape(String docString) {
return docString.replace("<", "&lt;").replace(">", "&gt;");
}

private static final Pattern CONSECUTIVE_BACKTICKS = Pattern.compile("`+");

/**
* Returns a Markdown code span (e.g. {@code `return foo;`}) that contains the given literal text,
* which may itself contain backticks.
*
* <p>For example:
*
* <ul>
* <li>{@code markdownCodeSpan("foo")} returns {@code "`foo`"}
* <li>{@code markdownCodeSpan("fo`o")} returns {@code "``fo`o``"}
* <li>{@code markdownCodeSpan("`foo`")} returns {@code "`` foo` ``""}
* </ul>
*/
public static String markdownCodeSpan(String code) {
// https://github.github.com/gfm/#code-span
int numConsecutiveBackticks =
CONSECUTIVE_BACKTICKS
.matcher(code)
.results()
.map(match -> match.end() - match.start())
.max(naturalOrder())
.orElse(0);
String padding = code.startsWith("`") || code.endsWith("`") ? " " : "";
return String.format(
"%1$s%2$s%3$s%2$s%1$s", "`".repeat(numConsecutiveBackticks + 1), padding, code);
}

/**
* Return a string representing the rule summary for the given rule with the given name.
*
Expand Down
1 change: 1 addition & 0 deletions src/test/java/com/google/devtools/build/skydoc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ filegroup(
testonly = 0,
srcs = glob(["**"]) + [
"//src/test/java/com/google/devtools/build/skydoc/private:srcs",
"//src/test/java/com/google/devtools/build/skydoc/rendering:srcs",
"//src/test/java/com/google/devtools/build/skydoc/testdata/same_level_file_test:srcs",
],
visibility = ["//src:__pkg__"],
Expand Down
24 changes: 24 additions & 0 deletions src/test/java/com/google/devtools/build/skydoc/rendering/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
load("@rules_java//java:defs.bzl", "java_test")

package(
default_applicable_licenses = ["//:license"],
default_visibility = ["//src:__subpackages__"],
)

filegroup(
name = "srcs",
testonly = 0,
srcs = glob(["*"]),
visibility = ["//src:__subpackages__"],
)

java_test(
name = "MarkdownUtilTest",
size = "small",
srcs = ["MarkdownUtilTest.java"],
deps = [
"//src/main/java/com/google/devtools/build/skydoc/rendering",
"//third_party:junit4",
"//third_party:truth",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2023 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.skydoc.rendering;

import static com.google.common.truth.Truth.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for MarkdownUtil. */
@RunWith(JUnit4.class)
public class MarkdownUtilTest {

MarkdownUtil util = new MarkdownUtil();

@Test
public void markdownCodeSpan() {
assertThat(MarkdownUtil.markdownCodeSpan("")).isEqualTo("``");
assertThat(MarkdownUtil.markdownCodeSpan("foo bar ")).isEqualTo("`foo bar `");
}

@Test
public void markdownCodeSpan_backticks() {
assertThat(MarkdownUtil.markdownCodeSpan("foo`bar")).isEqualTo("``foo`bar``");
assertThat(MarkdownUtil.markdownCodeSpan("foo``bar")).isEqualTo("```foo``bar```");
assertThat(MarkdownUtil.markdownCodeSpan("foo`bar```baz``quz"))
.isEqualTo("````foo`bar```baz``quz````");
}

@Test
public void markdownCodeSpan_backticksPadding() {
assertThat(MarkdownUtil.markdownCodeSpan("`foo")).isEqualTo("`` `foo ``");
assertThat(MarkdownUtil.markdownCodeSpan("``foo")).isEqualTo("``` ``foo ```");
assertThat(MarkdownUtil.markdownCodeSpan("foo`")).isEqualTo("`` foo` ``");
assertThat(MarkdownUtil.markdownCodeSpan("foo``")).isEqualTo("``` foo`` ```");
}
}

0 comments on commit 3d26048

Please sign in to comment.