com.bernardomg.velocity.tool.SiteTool Maven / Gradle / Ivy
/**
* The MIT License (MIT)
*
* Copyright (c) 2015-2023 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.bernardomg.velocity.tool;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.apache.velocity.tools.config.DefaultKey;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Tag;
/**
* Utilities class for fixing several issues in Doxia generated sites, updating and homogenising their layouts.
*
* This was created for Maven Sites. These are built through Doxia which supports XHTML, and not HTML5, and so this
* library generates outdated pages. Also some of the reports which can be generated through Maven plugins suffer from
* similar issues and add another problem, that their layouts may not match at all.
*
* The Docs Maven Skin and its requirements have dictated
* the development of this class. For more generic methods use the {@link com.bernardomg.velocity.tool.HtmlTool
* HtmlTool}.
*
* @author Bernardo Martínez Garrido
*/
@DefaultKey("siteTool")
public class SiteTool {
/**
* Regular expresion indicating invalid values for ids and internal links which will be replaced by hyphens.
*/
private static final String ID_HYPHEN_REGEX = "[ _]";
/**
* Regular expresion indicating invalid values for ids and internal links will will be removed.
*/
private static final String ID_REJECTED_REGEX = "[^\\w#-]";
/**
* Constructs an instance of the utilities class.
*/
public SiteTool() {
super();
}
/**
* Fixes links to anchors in the same page.
*
* Any link such as {@code A link} will be transformed into
* {@code A link}.
*
* The href value will receive the following modifications, only if it is an internal link:
*
* - Text will be set to lower case
* - Underscores will be removed
* - Points will be removed
* - Empty spaces will be removed
*
*
* @param root
* root element with anchors to fix
* @return transformed element
*/
public final Element fixAnchorLinks(final Element root) {
String ref; // Value of the href attribute
String id; // Formatted id
Objects.requireNonNull(root, "Received a null pointer as root element");
// Anchors
for (final Element anchor : root.getElementsByTag("a")) {
// If the attribute doesn't exist then the ref will be an empty
// string
ref = anchor.attr("href");
if ((!ref.isEmpty()) && ("#".equals(ref.substring(0, 1)))) {
id = formatId(ref);
anchor.attr("href", id);
}
}
return root;
}
/**
* Adds or fixes heading ids.
*
* If a heading has an id it will be corrected if needed, otherwise it will be created from the heading text.
*
* The following operations are applied during this process:
*
* - Text will be set to lower case
* - Underscores will be removed
* - Points will be removed
* - Empty spaces will be removed
*
*
* With this headings will end looking like {@code
A heading
}.
*
* @param root
* root element with headings where an id should be added
* @return transformed element
*/
public final Element fixHeadingIds(final Element root) {
final Collection headings; // Headings to fix
String idText; // Text to generate the id
String id; // Formatted id
Objects.requireNonNull(root, "Received a null pointer as root element");
// Table rows with tags in a
headings = root.select("h1,h2,h3,h4,h5,h6");
for (final Element heading : headings) {
if (heading.hasAttr("id")) {
// Contains an id
// The id text is taken from the attribute
idText = heading.attr("id");
} else {
// Doesn't contain an id
// The id text is taken from the heading text
idText = heading.text();
}
id = formatId(idText);
heading.attr("id", id);
}
return root;
}
/**
* Fixes a Maven Site report.
*
* This is prepared for the following reports:
*
* - Changes report
* - Checkstyle
* - CPD
* - Dependencies
* - Failsafe report
* - Findbugs
* - JDepend
* - License
* - Plugins
* - Plugin management
* - Project summary
* - PMD
* - Surefire report
* - Tags list
* - Team list
*
* Most of the times, the fix consists on correcting the heading levels, and adding an initial heading if needed.
*
* @param root
* root element with the report
* @param report
* the report name
* @return transformed element
*/
public final Element fixReport(final Element root, final String report) {
Objects.requireNonNull(root, "Received a null pointer as root element");
Objects.requireNonNull(report, "Received a null pointer as report");
switch (report) {
case "changes-report":
fixReportChanges(root);
break;
case "checkstyle":
case "checkstyle-aggregate":
fixReportCheckstyle(root);
break;
case "cpd":
fixReportCpd(root);
break;
case "dependencies":
fixReportDependencies(root);
break;
case "dependency-analysis":
fixReportDependencyAnalysis(root);
break;
case "failsafe-report":
fixReportFailsafe(root);
break;
case "findbugs":
case "spotbugs":
fixReportFindbugs(root);
break;
case "jdepend-report":
fixReportJdepend(root);
break;
case "license":
case "licenses":
fixReportLicense(root);
break;
case "plugins":
fixReportPlugins(root);
break;
case "plugin-management":
fixReportPluginManagement(root);
break;
case "pmd":
fixReportPmd(root);
break;
case "project-summary":
case "summary":
fixReportProjectSummary(root);
break;
case "surefire-report":
fixReportSurefire(root);
break;
case "taglist":
fixReportTaglist(root);
break;
case "team-list":
case "team":
fixReportTeamList(root);
break;
default:
break;
}
return root;
}
/**
* Transforms the default icons used by the Maven Site to Font Awesome icons.
*
* @param root
* root element with the page
* @return transformed element
*/
public final Element transformIcons(final Element root) {
final Map replacements; // Texts to replace and
// replacements
Objects.requireNonNull(root, "Received a null pointer as root element");
replacements = new HashMap<>();
replacements.put("img[src$=images/add.gif]",
"Addition");
replacements.put("img[src$=images/remove.gif]",
"Remove");
replacements.put("img[src$=images/fix.gif]",
"Fix");
replacements.put("img[src$=images/update.gif]",
"Refresh");
replacements.put("img[src$=images/icon_help_sml.gif]",
"Question");
replacements.put("img[src$=images/icon_success_sml.gif]",
"Passed");
replacements.put("img[src$=images/icon_warning_sml.gif]",
"Warning");
replacements.put("img[src$=images/icon_error_sml.gif]",
"Failed");
replacements.put("img[src$=images/icon_info_sml.gif]",
"Info");
replaceAll(root, replacements);
return root;
}
/**
* Transforms simple {@code } elements to {@code