Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

Process markdown cloud links for PHP #1091

Merged
merged 13 commits into from
May 26, 2017
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public final class CommentPatterns {
public static final Pattern BACK_QUOTE_PATTERN = Pattern.compile("(?<!`)``?(?!`)");
public static final Pattern ABSOLUTE_LINK_PATTERN =
Pattern.compile("\\[([^\\]]+)\\]\\((\\p{Alpha}+:[^\\)]+)\\)");
public static final Pattern CLOUD_LINK_PATTERN =
public static final Pattern RELATIVE_LINK_PATTERN =
Pattern.compile("\\[([^\\]]+)\\]\\(((?!\\p{Alpha}+:)[^\\)]+)\\)");
public static final Pattern PROTO_LINK_PATTERN =
Pattern.compile("\\[([^\\]]+)\\]\\[([A-Za-z_][A-Za-z_.0-9]*)?\\]");
Expand Down
103 changes: 103 additions & 0 deletions src/main/java/com/google/api/codegen/util/CommentTransformer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/* Copyright 2017 Google Inc
*
* 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.api.codegen.util;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CommentTransformer {

public static String CLOUD_URL_PREFIX = "https://cloud.google.com";

private ImmutableList<Transformation> transformations;

private CommentTransformer(ImmutableList<Transformation> transformations) {
this.transformations = transformations;
}

public String transform(String comment) {
for (Transformation transformation : transformations) {
comment = transformation.apply(comment);
}
return comment;
}

public static Builder newBuilder() {
return new Builder();
}

public static class Builder {

private ImmutableList.Builder<Transformation> transformations = ImmutableList.builder();

private Builder() {}

public Builder replace(Pattern pattern, final String replacement) {
transformations.add(
new Transformation(
pattern,
new Function<String, String>() {
@Override
public String apply(String s) {
return replacement;
}
}));
return this;
}

public Builder scopedReplace(Pattern pattern, final String target, final String replacement) {
return transform(
new Transformation(
pattern,
new Function<String, String>() {
@Override
public String apply(String matchedString) {
return matchedString.replace(target, replacement);
}
}));
}

public Builder transform(Transformation transformation) {
transformations.add(transformation);
return this;
}

public CommentTransformer build() {
return new CommentTransformer(transformations.build());
}
}

public static class Transformation {
private Pattern pattern;
private Function<String, String> replacementFunction;

public Transformation(Pattern pattern, Function<String, String> replacementFunction) {
this.pattern = pattern;
this.replacementFunction = replacementFunction;
}

public String apply(String comment) {
StringBuffer sb = new StringBuffer();
Matcher m = pattern.matcher(comment);
while (m.find()) {
m.appendReplacement(sb, replacementFunction.apply(m.group()));
}
m.appendTail(sb);
return sb.toString();
}
}
}
73 changes: 73 additions & 0 deletions src/main/java/com/google/api/codegen/util/LinkPattern.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* Copyright 2017 Google Inc
*
* 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.api.codegen.util;

import com.google.api.codegen.CommentPatterns;
import com.google.api.codegen.util.CommentTransformer.Transformation;
import com.google.common.base.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* An collection of known link patterns found in proto files. The LinkPattern class provides an easy
* way to create Transformation objects for these link patterns into a particular format.
*
* <p>The format may contain standard Java string format tokens, or the special tokens $TITLE and
* $URL.
*
* <p>An example creating a Transformation for a relative link would be:
*
* <pre>
* <code>
* Transformation transformation = LinkPattern.RELATIVE
* .withUrlPrefix("https://cloud.google.com")
* .toFormat("[$TITLE]($URL)"));
* </code>
* </pre>
*/
public class LinkPattern {
public static LinkPattern ABSOLUTE = new LinkPattern(CommentPatterns.ABSOLUTE_LINK_PATTERN, "");
public static LinkPattern RELATIVE = new LinkPattern(CommentPatterns.RELATIVE_LINK_PATTERN, "");
public static LinkPattern PROTO = new LinkPattern(CommentPatterns.PROTO_LINK_PATTERN, "");

private Pattern pattern;
private String urlPrefix;

private LinkPattern(Pattern pattern, String urlPrefix) {
this.pattern = pattern;
this.urlPrefix = urlPrefix;
}

public LinkPattern withUrlPrefix(String urlPrefix) {
return new LinkPattern(pattern, urlPrefix);
}

public Transformation toFormat(String linkFormat) {
final String finalLinkFormat =
linkFormat.replaceAll("\\$TITLE", "%1\\$s").replaceAll("\\$URL", "%2\\$s");
return new Transformation(
pattern,
new Function<String, String>() {
@Override
public String apply(String matchedString) {
Matcher matcher = pattern.matcher(matchedString);
matcher.find();
String title = matcher.group(1);
String url = urlPrefix + matcher.group(2);
return Matcher.quoteReplacement(String.format(finalLinkFormat, title, url));
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,27 @@
*/
package com.google.api.codegen.util.js;

import com.google.api.codegen.CommentPatterns;
import com.google.api.codegen.util.CommentReformatter;
import com.google.api.codegen.util.CommentTransformer;
import com.google.api.codegen.util.LinkPattern;
import com.google.api.tools.framework.model.ProtoElement;
import com.google.api.tools.framework.model.ProtoFile;
import com.google.common.collect.ImmutableSet;
import java.util.regex.Matcher;

public class JSCommentReformatter implements CommentReformatter {
@Override
public String reformat(String comment) {
comment = reformatProtoMarkdownLinks(comment);
comment = reformatCloudMarkdownLinks(comment);
return comment.trim();
}

/** Returns a string with all proto markdown links formatted to JSDoc style. */
private String reformatProtoMarkdownLinks(String comment) {
StringBuffer sb = new StringBuffer();
Matcher m = CommentPatterns.PROTO_LINK_PATTERN.matcher(comment);
if (!m.find()) {
return comment;
}
do {
// proto display name may contain '$' which needs to be escaped using Matcher.quoteReplacement
m.appendReplacement(sb, Matcher.quoteReplacement(String.format("{@link %s}", m.group(1))));
} while (m.find());
m.appendTail(sb);
return sb.toString();
}
private CommentTransformer transformer =
CommentTransformer.newBuilder()
.transform(LinkPattern.PROTO.toFormat("{@link $TITLE}"))
.transform(
LinkPattern.RELATIVE
.withUrlPrefix(CommentTransformer.CLOUD_URL_PREFIX)
.toFormat("[$TITLE]($URL)"))
.build();

/** Returns a string with all cloud markdown links formatted to JSDoc style. */
private String reformatCloudMarkdownLinks(String comment) {
StringBuffer sb = new StringBuffer();
Matcher m = CommentPatterns.CLOUD_LINK_PATTERN.matcher(comment);
if (!m.find()) {
return comment;
}
do {
String url = "https://cloud.google.com" + m.group(2);
// cloud markdown links may contain '$' which needs to be escaped using Matcher.quoteReplacement
m.appendReplacement(sb, Matcher.quoteReplacement(String.format("[%s](%s)", m.group(1), url)));
} while (m.find());
m.appendTail(sb);
return sb.toString();
@Override
public String reformat(String comment) {
return transformer.transform(comment).trim();
}

public String getLinkedElementName(ProtoElement element) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,26 @@
package com.google.api.codegen.util.php;

import com.google.api.codegen.util.CommentReformatter;
import com.google.common.escape.Escaper;
import com.google.common.escape.Escapers;
import com.google.api.codegen.util.CommentTransformer;
import com.google.api.codegen.util.LinkPattern;
import java.util.regex.Pattern;

public class PhpCommentReformatter implements CommentReformatter {
/** Escaper for formatting PHP doc strings. */
private static final Escaper PHP_ESCAPER =
Escapers.builder().addEscape('*', "&#42;").addEscape('@', "&#64;").build();
public static final Pattern ASTERISK_PATTERN = Pattern.compile("\\*");
public static final Pattern AMPERSAND_PATTERN = Pattern.compile("@");

private CommentTransformer transformer =
CommentTransformer.newBuilder()
.replace(ASTERISK_PATTERN, "&#42;")
.replace(AMPERSAND_PATTERN, "&#64;")
.transform(
LinkPattern.RELATIVE
.withUrlPrefix(CommentTransformer.CLOUD_URL_PREFIX)
.toFormat("[$TITLE]($URL)"))
.build();

@Override
public String reformat(String comment) {
return PHP_ESCAPER.escape(comment).trim();
return transformer.transform(comment).trim();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,23 @@

import com.google.api.codegen.CommentPatterns;
import com.google.api.codegen.util.CommentReformatter;
import com.google.api.codegen.util.CommentTransformer;
import com.google.api.codegen.util.LinkPattern;
import com.google.common.base.Splitter;
import java.util.regex.Matcher;

public class PythonCommentReformatter implements CommentReformatter {

private CommentTransformer transformer =
CommentTransformer.newBuilder()
.replace(CommentPatterns.BACK_QUOTE_PATTERN, "``")
.transform(LinkPattern.PROTO.toFormat("``$TITLE``"))
.transform(LinkPattern.ABSOLUTE.toFormat("`$TITLE <$URL>`_"))
.transform(
LinkPattern.RELATIVE
.withUrlPrefix(CommentTransformer.CLOUD_URL_PREFIX)
.toFormat("`$TITLE <$URL>`_"))
.build();

@Override
public String reformat(String comment) {
boolean inCodeBlock = false;
Expand All @@ -32,15 +45,15 @@ public String reformat(String comment) {
if (!(line.trim().isEmpty()
|| CommentPatterns.CODE_BLOCK_PATTERN.matcher(line).matches())) {
inCodeBlock = false;
line = applyTransformations(line);
line = transformer.transform(line);
}

} else if (CommentPatterns.CODE_BLOCK_PATTERN.matcher(line).matches()) {
inCodeBlock = true;
line = "::\n\n" + line;

} else {
line = applyTransformations(line);
line = transformer.transform(line);
}

if (!first) {
Expand All @@ -51,60 +64,4 @@ public String reformat(String comment) {
}
return sb.toString().trim();
}

private String applyTransformations(String line) {
line = CommentPatterns.BACK_QUOTE_PATTERN.matcher(line).replaceAll("``");
line = reformatProtoMarkdownLinks(line);
line = reformatAbsoluteMarkdownLinks(line);
return reformatCloudMarkdownLinks(line);
}

/** Returns a string with all proto markdown links formatted to Sphinx style. */
private String reformatProtoMarkdownLinks(String comment) {
StringBuffer sb = new StringBuffer();
Matcher m = CommentPatterns.PROTO_LINK_PATTERN.matcher(comment);
if (!m.find()) {
return comment;
}
do {
// proto display name may contain '$' which needs to be escaped using Matcher.quoteReplacement
m.appendReplacement(sb, Matcher.quoteReplacement(String.format("``%s``", m.group(1))));
} while (m.find());
m.appendTail(sb);
return sb.toString();
}

/** Returns a string with all absolute markdown links formatted to Sphinx style. */
private String reformatAbsoluteMarkdownLinks(String comment) {
StringBuffer sb = new StringBuffer();
Matcher m = CommentPatterns.ABSOLUTE_LINK_PATTERN.matcher(comment);
if (!m.find()) {
return comment;
}
do {
// absolute markdown links may contain '$' which needs to be escaped using Matcher.quoteReplacement
m.appendReplacement(
sb, Matcher.quoteReplacement(String.format("`%s <%s>`_", m.group(1), m.group(2))));
} while (m.find());
m.appendTail(sb);
return sb.toString();
}

/** Returns a string with all cloud markdown links formatted to Sphinx style. */
private String reformatCloudMarkdownLinks(String comment) {
StringBuffer sb = new StringBuffer();
Matcher m = CommentPatterns.CLOUD_LINK_PATTERN.matcher(comment);
if (!m.find()) {
return comment;
}
do {
// cloud markdown links may contain '$' which needs to be escaped using Matcher.quoteReplacement
m.appendReplacement(
sb,
Matcher.quoteReplacement(
String.format("`%s <https://cloud.google.com%s>`_", m.group(1), m.group(2))));
} while (m.find());
m.appendTail(sb);
return sb.toString();
}
}
Loading