Skip to content

Commit

Permalink
Expose Links in Catalog
Browse files Browse the repository at this point in the history
Add new Link interface and accessors methods to Catalog interface.
Original links in asciidoctor are just a string but here we wrap them
in an object to protect from future evolutions.

Fixes asciidoctor#1183
  • Loading branch information
abelsromero committed Apr 21, 2023
1 parent 8603b64 commit 03968ff
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Improvement::
* Remove class `AsciidoctorUtils` to remove complexity and unused logging (#1169) (@abelsromero)
* Expose ImageReferences in the catalog (#1166) (@abelsromero)
* Return Document AST when using convert or convertFile with appropriate options (#1171) (@abelsromero)
* Expose Links in the catalog (#1183) (@abelsromero)

Bug Fixes::

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ public interface Catalog {
*/
List<ImageReference> getImages();

/**
* Retrieves the images from the source document.
* Note that inline images are only available after `Document.getContent()` has been called.
*
* @return images occurring in document.
*/
List<Link> getLinks();

/**
* Refs is a map of asciidoctor ids to asciidoctor document elements.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
package org.asciidoctor.ast;

/**
* Image reference view as available in the assets catalog.
*
* @since 3.0.0
*/
public interface ImageReference {

/**
* The image target describing the image location.
* The target may be a path or a URL.
*
* @return image target
*/
String getTarget();

/**
* Value of the 'imagesdir' attribute applied to resolve the image location.
*
* @return imagesdir value
*/
String getImagesdir();
}
17 changes: 17 additions & 0 deletions asciidoctorj-api/src/main/java/org/asciidoctor/ast/Link.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.asciidoctor.ast;

/**
* Link view as available in the assets catalog.
*
* @since 3.0.0
*/
public interface Link {

/**
* The resolved path of the link.
* The text may be a file path or a URL.
*
* @return The link path including substitutions being applied.
*/
String getText();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.asciidoctor.ast.Catalog;
import org.asciidoctor.ast.Footnote;
import org.asciidoctor.ast.ImageReference;
import org.asciidoctor.ast.Link;
import org.asciidoctor.jruby.internal.RubyHashMapDecorator;
import org.jruby.RubyArray;
import org.jruby.RubyHash;
Expand Down Expand Up @@ -37,6 +38,14 @@ public List<ImageReference> getImages() {
.collect(Collectors.toUnmodifiableList());
}

@Override
public List<Link> getLinks() {
return (List<Link>) ((RubyArray) catalog.get("links"))
.stream()
.map(o -> LinkImpl.getInstance((String) o))
.collect(Collectors.toUnmodifiableList());
}

@Override
public Map<String, Object> getRefs() {
Map<String, Object> refs = new RubyHashMapDecorator((RubyHash) catalog.get("refs"), String.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ private ImageReferenceImpl(String target, String imagesdir) {
this.imagesdir = imagesdir;
}

static ImageReference getInstance(RubyStruct rubyFootnote) {
final String target = (String) aref(rubyFootnote, TARGET_KEY_NAME);
final String imagesdir = (String) aref(rubyFootnote, IMAGESDIR_KEY_NAME);
static ImageReference getInstance(RubyStruct rubyStruct) {
final String target = (String) aref(rubyStruct, TARGET_KEY_NAME);
final String imagesdir = (String) aref(rubyStruct, IMAGESDIR_KEY_NAME);
return new ImageReferenceImpl(target, imagesdir);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.asciidoctor.jruby.ast.impl;

import org.asciidoctor.ast.Link;

public class LinkImpl implements Link {

private final String text;

private LinkImpl(String text) {
this.text = text;
}

static Link getInstance(String value) {
return new LinkImpl(value);
}

@Override
public String getText() {
return text;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package org.asciidoctor.jruby.internal;

import org.asciidoctor.Asciidoctor;
import org.asciidoctor.Options;
import org.asciidoctor.SafeMode;
import org.asciidoctor.arquillian.api.Unshared;
import org.asciidoctor.ast.Document;
import org.asciidoctor.ast.Link;
import org.asciidoctor.util.ClasspathResources;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(Arquillian.class)
public class WhenReadingLinksFromCatalogAsset {

@ArquillianResource
private ClasspathResources classpath;

@ArquillianResource(Unshared.class)
private Asciidoctor asciidoctor;

@ArquillianResource
private TemporaryFolder testFolder;

static final String[] ALL_LINKS = new String[]{
"https://docs.asciidoctor.org",
"https://github.com",
"https://some.rangomsite.org",
"downloads/report.pdf"
};

@Test
public void shouldReturnEmptyWhenThereAreNoLinks() {
final Options options = catalogAssetsEnabled();

Document document = asciidoctor.load("= Hello", options);
List<Link> links = document.getCatalog().getLinks();

assertThat(links)
.isEmpty();
}

@Test
public void shouldNotReturnLinksWhenNotConverting() {
final Options options = catalogAssetsEnabled();
final String content = getAsciiDocWithLinksContent();

Document document = asciidoctor.load(content, options);
List<Link> links = document.getCatalog().getLinks();

assertThat(links)
.isEmpty();
}

@Test
public void shouldNotReturnLinksWhenCatalogAssetsIsFalse() {
final Options options = Options.builder()
.catalogAssets(false)
.build();
final File file = getAsciiDocWithLinksFile();

Document document = asciidoctor.convertFile(file, options, Document.class);

List<Link> links = document.getCatalog().getLinks();
assertThat(links)
.isEmpty();
}

@Test
public void shouldReturnLinksWhenConvertingFile() {
final Options options = catalogAssetsEnabled();
final File file = getAsciiDocWithLinksFile();

Document document = asciidoctor.convertFile(file, options, Document.class);

List<Link> links = document.getCatalog().getLinks();
assertThat(links)
.map(link -> link.getText())
.containsExactlyInAnyOrder(ALL_LINKS);
}

@Test
public void shouldReturnLinksWhenConvertingString() throws IOException {
final Options options = Options.builder()
.catalogAssets(true)
.safe(SafeMode.UNSAFE)
.toFile(testFolder.newFile())
.build();
final String content = getAsciiDocWithLinksContent();

Document document = asciidoctor.convert(content, options, Document.class);

List<Link> links = document.getCatalog().getLinks();
assertThat(links)
.map(link -> link.getText())
.containsExactlyInAnyOrder(ALL_LINKS);
}

private String getAsciiDocWithLinksContent() {
try {
return Files.readString(getAsciiDocWithLinksFile().toPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private File getAsciiDocWithLinksFile() {
return classpath.getResource("sample-with-links.adoc");
}

private static Options catalogAssetsEnabled() {
return Options.builder()
.catalogAssets(true)
.build();
}
}
9 changes: 9 additions & 0 deletions asciidoctorj-core/src/test/resources/sample-with-links.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
= This is a title
:site-host: some.rangomsite.org

You can learn about Asciidoctor at https://docs.asciidoctor.org.
The Asciidoctor source repo is hosted on https://github.com[GitHub].

== A few links

You can also use attributes for links like in https://{site-host}, or use full syntax for files link:downloads/report.pdf[Get Report].

0 comments on commit 03968ff

Please sign in to comment.