001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.site; 021 022import java.util.Set; 023 024import org.apache.maven.doxia.macro.AbstractMacro; 025import org.apache.maven.doxia.macro.Macro; 026import org.apache.maven.doxia.macro.MacroExecutionException; 027import org.apache.maven.doxia.macro.MacroRequest; 028import org.apache.maven.doxia.module.xdoc.XdocSink; 029import org.apache.maven.doxia.sink.Sink; 030import org.codehaus.plexus.component.annotations.Component; 031 032/** 033 * A macro that inserts a list of the violation messages. 034 */ 035@Component(role = Macro.class, hint = "violation-messages") 036public class ViolationMessagesMacro extends AbstractMacro { 037 @Override 038 public void execute(Sink sink, MacroRequest request) throws MacroExecutionException { 039 // until https://github.com/checkstyle/checkstyle/issues/13426 040 if (!(sink instanceof XdocSink)) { 041 throw new MacroExecutionException("Expected Sink to be an XdocSink."); 042 } 043 final String checkName = (String) request.getParameter("checkName"); 044 final Object instance = SiteUtil.getModuleInstance(checkName); 045 final Class<?> clss = instance.getClass(); 046 final Set<String> messageKeys = SiteUtil.getMessageKeys(clss); 047 createListOfMessages((XdocSink) sink, clss, messageKeys); 048 } 049 050 /** 051 * Iterates through the fields of the class and creates an unordered list. 052 * 053 * @param sink the sink to write to. 054 * @param clss the class of the fields. 055 * @param messageKeys the List of message keys to iterate through. 056 */ 057 private static void createListOfMessages( 058 XdocSink sink, Class<?> clss, Set<String> messageKeys) { 059 final String indentLevel8 = SiteUtil.getNewlineAndIndentSpaces(8); 060 061 // This is a hack to prevent a newline from being inserted by the default sink. 062 // Once we get rid of the custom parser, we can remove this. 063 // until https://github.com/checkstyle/checkstyle/issues/13426 064 sink.setInsertNewline(false); 065 sink.list(); 066 sink.setInsertNewline(true); 067 068 for (String messageKey : messageKeys) { 069 createListItem(sink, clss, messageKey); 070 } 071 sink.rawText(indentLevel8); 072 sink.list_(); 073 } 074 075 /** 076 * Creates a list item for the given field. 077 * 078 * @param sink the sink to write to. 079 * @param clss the class of the field. 080 * @param messageKey the message key. 081 */ 082 private static void createListItem(XdocSink sink, Class<?> clss, String messageKey) { 083 final String messageKeyUrl = constructMessageKeyUrl(clss, messageKey); 084 final String indentLevel10 = SiteUtil.getNewlineAndIndentSpaces(10); 085 final String indentLevel12 = SiteUtil.getNewlineAndIndentSpaces(12); 086 final String indentLevel14 = SiteUtil.getNewlineAndIndentSpaces(14); 087 // Place the <li>. 088 sink.rawText(indentLevel10); 089 // This is a hack to prevent a newline from being inserted by the default sink. 090 // Once we get rid of the custom parser, we can remove this. 091 // until https://github.com/checkstyle/checkstyle/issues/13426 092 sink.setInsertNewline(false); 093 sink.listItem(); 094 sink.setInsertNewline(true); 095 096 // Place an <a>. 097 sink.rawText(indentLevel12); 098 sink.link(messageKeyUrl); 099 // Further indent the text. 100 sink.rawText(indentLevel14); 101 sink.rawText(messageKey); 102 103 // Place closing </a> and </li> tags. 104 sink.rawText(indentLevel12); 105 sink.link_(); 106 sink.rawText(indentLevel10); 107 sink.listItem_(); 108 } 109 110 /** 111 * Constructs a URL to GitHub that searches for the message key. 112 * 113 * @param clss the class of the module. 114 * @param messageKey the message key. 115 * @return the URL to GitHub. 116 */ 117 private static String constructMessageKeyUrl(Class<?> clss, String messageKey) { 118 return "https://github.com/search?q=" 119 + "path%3Asrc%2Fmain%2Fresources%2F" 120 + clss.getPackage().getName().replace(".", "%2F") 121 + "%20path%3A**%2Fmessages*.properties+repo%3Acheckstyle%2F" 122 + "checkstyle+%22" + messageKey + "%22"; 123 } 124}