Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.commonmark.ext.autolink;

import java.util.EnumSet;
import java.util.Set;

import org.commonmark.Extension;
import org.commonmark.ext.autolink.internal.AutolinkPostProcessor;
import org.commonmark.parser.Parser;
Expand All @@ -18,16 +21,75 @@
*/
public class AutolinkExtension implements Parser.ParserExtension {

private AutolinkExtension() {
private final Set<AutolinkType> linkTypes;

private AutolinkExtension(Builder builder) {
this.linkTypes = builder.linkTypes;
}

/**
* @return the extension with default options
*/
public static Extension create() {
return new AutolinkExtension();
return builder().build();
}

/**
* @return a builder to configure the behavior of the extension.
*/
public static Builder builder() {
return new Builder();
}

@Override
public void extend(Parser.Builder parserBuilder) {
parserBuilder.postProcessor(new AutolinkPostProcessor());
parserBuilder.postProcessor(new AutolinkPostProcessor(linkTypes));
}

public static class Builder {

private Set<AutolinkType> linkTypes = EnumSet.of(AutolinkType.URL, AutolinkType.EMAIL);

/**
* @param linkTypes the link types that should be converted. By default, {@link AutolinkType#URL}
* and {@link AutolinkType#EMAIL} are converted.
* @return {@code this}
*/
public Builder linkTypes(AutolinkType... linkTypes) {
if (linkTypes == null) {
throw new NullPointerException("linkTypes must not be null");
}

if (linkTypes.length == 0) {
throw new IllegalArgumentException("linkTypes must not be empty");
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to duplicate the checks above if we're delegating to linkTypes(Set<AutolinkType> linkTypes) anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the second check. The first check was just to provide a more explicit error message than whatever is thrown by calling Set.of(null), but I can remove if we think that's unnecessary.


return this.linkTypes(Set.of(linkTypes));
}

/**
* @param linkTypes the link types that should be converted. By default, {@link AutolinkType#URL}
* and {@link AutolinkType#EMAIL} are converted.
* @return {@code this}
*/
public Builder linkTypes(Set<AutolinkType> linkTypes) {
if (linkTypes == null) {
throw new NullPointerException("linkTypes must not be null");
}

if (linkTypes.isEmpty()) {
throw new IllegalArgumentException("linkTypes must not be empty");
}

this.linkTypes = EnumSet.copyOf(linkTypes);
return this;
}

/**
* @return a configured extension
*/
public Extension build() {
return new AutolinkExtension(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.commonmark.ext.autolink;

public enum AutolinkType {
/**
* URL such as {@code http://example.com}
*/
URL,
/**
* Email address such as {@code [email protected]}
*/
EMAIL,
/**
* URL such as {@code www.example.com}
*/
WWW
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.commonmark.ext.autolink.internal;

import org.commonmark.ext.autolink.AutolinkType;
import org.commonmark.node.*;
import org.commonmark.parser.PostProcessor;
import org.nibor.autolink.LinkExtractor;
Expand All @@ -11,9 +12,40 @@

public class AutolinkPostProcessor implements PostProcessor {

private LinkExtractor linkExtractor = LinkExtractor.builder()
.linkTypes(EnumSet.of(LinkType.URL, LinkType.EMAIL))
.build();
private final LinkExtractor linkExtractor;

public AutolinkPostProcessor() {
this(EnumSet.of(AutolinkType.URL, AutolinkType.EMAIL));
}

public AutolinkPostProcessor(Set<AutolinkType> linkTypes) {
if (linkTypes == null) {
throw new NullPointerException("linkTypes must not be null");
}

if (linkTypes.isEmpty()) {
throw new IllegalArgumentException("linkTypes must not be empty");
}

EnumSet<LinkType> types = EnumSet.noneOf(LinkType.class);
for (AutolinkType linkType : linkTypes) {
switch (linkType) {
case URL:
types.add(LinkType.URL);
break;
case EMAIL:
types.add(LinkType.EMAIL);
break;
case WWW:
types.add(LinkType.WWW);
break;
}
}

this.linkExtractor = LinkExtractor.builder()
.linkTypes(types)
.build();
}

@Override
public Node process(Node node) {
Expand Down Expand Up @@ -67,8 +99,12 @@ private static Text createTextNode(String literal, Span span, SourceSpan sourceS
}

private static String getDestination(LinkSpan linkSpan, String linkText) {
if (linkSpan.getType() == LinkType.EMAIL) {
LinkType type = linkSpan.getType();

if (type == LinkType.EMAIL) {
return "mailto:" + linkText;
} else if (type == LinkType.WWW) {
return "http://" + linkText;
} else {
return linkText;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ public class AutolinkTest extends RenderingTestCase {
private static final Parser PARSER = Parser.builder().extensions(EXTENSIONS).build();
private static final HtmlRenderer RENDERER = HtmlRenderer.builder().extensions(EXTENSIONS).build();

private static final Set<Extension> WWW_EXTENSIONS = Set.of(AutolinkExtension.builder()
.linkTypes(AutolinkType.URL, AutolinkType.EMAIL, AutolinkType.WWW)
.build());
private static final Parser WWW_PARSER = Parser.builder().extensions(WWW_EXTENSIONS).build();
private static final HtmlRenderer WWW_RENDERER = HtmlRenderer.builder().extensions(WWW_EXTENSIONS).build();

@Test
public void oneTextNode() {
assertRendering("foo http://one.org/ bar http://two.org/",
Expand Down Expand Up @@ -57,6 +63,18 @@ public void dontLinkTextWithinLinks() {
"<p><a href=\"http://example.com\">http://example.com</a></p>\n");
}

@Test
public void wwwLinksDontWorkByDefault() {
assertRendering("www.example.com",
"<p>www.example.com</p>\n");
}

@Test
public void wwwLinks() {
String html = WWW_RENDERER.render(WWW_PARSER.parse("www.example.com"));
assertThat(html).isEqualTo("<p><a href=\"http://www.example.com\">www.example.com</a></p>\n");
}

@Test
public void sourceSpans() {
Parser parser = Parser.builder()
Expand Down