Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Expand Up @@ -12,6 +12,7 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2024 3A Systems LLC.
* Portions Copyright 2026 3A Systems, LLC.
*/

package org.openidentityplatform.doc.maven;
Expand All @@ -30,7 +31,9 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -89,6 +92,7 @@ private void convertPartialsForAntora(Path productPath, File docDir) throws IOEx
File[] docFiles = docDir.listFiles();
for (File docFile : docFiles) {
String adoc = FileUtils.readFileToString(docFile, StandardCharsets.UTF_8);
warnLegacyLinks(docFile, adoc);
adoc = convertForAntora(adoc);

Path convertedFilePath = Paths.get(partialsPath.toString(), docFile.getName());
Expand Down Expand Up @@ -126,23 +130,24 @@ private void convertDocForAntora(Path productPath, File docDir) throws IOExcepti
FileUtils.writeStringToFile(navFilePath.toFile(), nav, StandardCharsets.UTF_8);
} else {
Path convertedFilePath = Paths.get(docModulePagesPath.toString(), docFile.getName());
warnLegacyLinks(docFile, adoc);
adoc = convertForAntora(adoc);
FileUtils.writeStringToFile(convertedFilePath.toFile(), adoc, StandardCharsets.UTF_8);
}
}
}

private String convertForAntora(String adoc) {
static String convertForAntora(String adoc) {
adoc = adoc.replace("image::images/", "image::ROOT:");
adoc = adoc.replace("image:images/", "image:ROOT:");
adoc = adoc.replace("include::../partials/", "include::ROOT:partial$");
adoc = adoc.replace("link:../attachments/", "xref:ROOT:attachment$");
adoc = adoc.replace(":table-caption!:", ":table-caption!:\n:leveloffset: -1\"");
adoc = adoc.replace(":table-caption!:", ":table-caption!:\n:leveloffset: -1");
adoc = convertXrefsToAntora(adoc);
return adoc;
}

private String convertXrefsToAntora(String adoc) {
static String convertXrefsToAntora(String adoc) {
Pattern p = Pattern.compile("xref\\:(.+?)\\[");

Matcher m = p.matcher(adoc);
Expand All @@ -152,6 +157,7 @@ private String convertXrefsToAntora(String adoc) {
builder.append(adoc, i, m.start());
String url = m.group(1);
url = url.replace("../", "");
url = url.replaceAll("(^|/)(\\./)+", "$1");
url = url.replace("/", ":");

builder.append("xref:").append(url).append("[");
Expand All @@ -162,6 +168,28 @@ private String convertXrefsToAntora(String adoc) {
return builder.toString();
}

private static final Pattern LEGACY_LINK_PATTERN = Pattern.compile("link:\\.\\./\\.\\./\\.\\./[^\\[\\s]*");

/**
* Finds ForgeRock-era cross-guide links such as {@code link:../../../openam/13/admin-guide/}.
* They are not converted and resolve to 404 on the Antora site.
*/
static List<String> findLegacyLinks(String adoc) {
List<String> links = new ArrayList<>();
Matcher m = LEGACY_LINK_PATTERN.matcher(adoc);
while (m.find()) {
links.add(m.group());
}
return links;
}

void warnLegacyLinks(File docFile, String adoc) {
for (String link : findLegacyLinks(adoc)) {
getLog().warn("Legacy cross-guide link is not converted and will be broken in Antora: "
+ docFile + ": " + link);
}
}

private void createIndexForRoot() throws IOException, MojoExecutionException {
Path rootPath = getRootModulePath();
Path pagesPath = Paths.get(rootPath.toString(), "pages");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2024 3A Systems LLC.
* Portions Copyright 2026 3A Systems, LLC.
*/

package org.openidentityplatform.doc.maven;

import org.apache.maven.plugin.logging.SystemStreamLog;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

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

Expand All @@ -47,4 +51,62 @@ public void testExecute() throws Exception {
this.configureMojo(antoraMojo, "doc-maven-plugin", pom);
this.getVariablesAndValuesFromObject(antoraMojo);
}
}

@Test
public void testConvertXrefWithCurrentDirPrefix() {
assertThat(AntoraMojo.convertXrefsToAntora(
"see xref:./chap-jee-agent-config.adoc#configure-j2ee-policy-agent[Configure]"))
.isEqualTo("see xref:chap-jee-agent-config.adoc#configure-j2ee-policy-agent[Configure]");
}

@Test
public void testConvertXrefWithRepeatedCurrentDirSegments() {
assertThat(AntoraMojo.convertXrefsToAntora("xref:./././a.adoc[A]"))
.isEqualTo("xref:a.adoc[A]");
assertThat(AntoraMojo.convertXrefsToAntora("xref:a/././b.adoc[B]"))
.isEqualTo("xref:a:b.adoc[B]");
assertThat(AntoraMojo.convertXrefsToAntora("xref:../mod/././p.adoc[P]"))
.isEqualTo("xref:mod:p.adoc[P]");
}

@Test
public void testConvertXrefToOtherModule() {
assertThat(AntoraMojo.convertXrefsToAntora("xref:../reference/./ch02.adoc#anchor[Ref]"))
.isEqualTo("xref:reference:ch02.adoc#anchor[Ref]");
assertThat(AntoraMojo.convertXrefsToAntora("xref:ch02.adoc[Ref]"))
.isEqualTo("xref:ch02.adoc[Ref]");
}

@Test
public void testLeveloffsetHasNoStrayQuote() {
assertThat(AntoraMojo.convertForAntora(":table-caption!:\n"))
.isEqualTo(":table-caption!:\n:leveloffset: -1\n");
}

@Test
public void testFindLegacyLinks() {
assertThat(AntoraMojo.findLegacyLinks(
"link:../../../openam/13/admin-guide/#chap-cdsso[CDSSO] and "
+ "link:../attachments/file.zip[file] and "
+ "link:../../../opendj/3.5/admin-guide/[OpenDJ]"))
.containsExactly("link:../../../openam/13/admin-guide/#chap-cdsso",
"link:../../../opendj/3.5/admin-guide/");
}

@Test
public void testWarnLegacyLinksNamesFileAndLink() {
AntoraMojo mojo = new AntoraMojo();
List<String> warnings = new ArrayList<>();
mojo.setLog(new SystemStreamLog() {
@Override
public void warn(CharSequence content) {
warnings.add(content.toString());
}
});
mojo.warnLegacyLinks(new File("chap-cdsso.adoc"),
"link:../../../openam/13/admin-guide/#chap-cdsso[CDSSO]");
assertThat(warnings).hasSize(1);
assertThat(warnings.get(0))
.contains("chap-cdsso.adoc", "link:../../../openam/13/admin-guide/#chap-cdsso");
}
}
Loading