001/* 002 * Copyright 2013-2024 John Ericksen 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.asciidoctor.asciidoclet; 017 018import jdk.javadoc.doclet.Doclet; 019import jdk.javadoc.doclet.DocletEnvironment; 020import jdk.javadoc.doclet.Reporter; 021import jdk.javadoc.doclet.StandardDoclet; 022 023import javax.lang.model.SourceVersion; 024import java.io.IOException; 025import java.io.UncheckedIOException; 026import java.util.Arrays; 027import java.util.HashSet; 028import java.util.Locale; 029import java.util.Set; 030 031/** 032 * = Asciidoclet 033 * <p> 034 * https://github.com/asciidoctor/asciidoclet[Asciidoclet] is a Javadoc Doclet 035 * that uses https://asciidoctor.org[Asciidoctor] (via the 036 * https://github.com/asciidoctor/asciidoctorj[Asciidoctor Java integration]) 037 * to interpret https://asciidoc.org[AsciiDoc] markup within Javadoc comments. 038 * <p> 039 * include::README.adoc[tags=usage] 040 * <p> 041 * == Examples 042 * <p> 043 * Custom attributes:: 044 * `+{project_name}+`;; {project_name} 045 * `+{project_desc}+`;; {project_desc} 046 * `+{project_version}+`;; {project_version} 047 * <p> 048 * Code block (with syntax highlighting added by CodeRay):: 049 * + 050 * [source,java] 051 * -- 052 * /** 053 * * = Asciidoclet 054 * * 055 * * A Javadoc Doclet that uses https://asciidoctor.org[Asciidoctor] 056 * * to render https://asciidoc.org[AsciiDoc] markup in Javadoc comments. 057 * * 058 * * @author https://github.com/johncarl81[John Ericksen] 059 * *\/ 060 * public class Asciidoclet extends Doclet { 061 * private final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); // <1> 062 * 063 * @author https://github.com/johncarl81[John Ericksen] 064 * @version {project_version} 065 * @SuppressWarnings("UnusedDeclaration") public static boolean start(RootDoc rootDoc) { 066 * new Asciidoclet().render(rootDoc); // <2> 067 * return Standard.start(rootDoc); 068 * } 069 * } 070 * -- 071 * <1> Creates an instance of the Asciidoctor Java integration 072 * <2> Runs Javadoc comment strings through Asciidoctor 073 * <p> 074 * Inline code:: `code()` 075 * <p> 076 * Headings:: 077 * + 078 * -- 079 * [float] 080 * = Heading 1 081 * <p> 082 * [float] 083 * == Heading 2 084 * <p> 085 * [float] 086 * === Heading 3 087 * <p> 088 * [float] 089 * ==== Heading 4 090 * <p> 091 * [float] 092 * ===== Heading 5 093 * -- 094 * <p> 095 * Links:: 096 * Doc Writer <doc@example.com> + 097 * https://asciidoc.org[AsciiDoc] is a lightweight markup language. + 098 * Learn more about it at https://asciidoctor.org. + 099 * <p> 100 * Bullets:: 101 * + 102 * -- 103 * .Unnumbered 104 * * bullet 105 * * bullet 106 * - bullet 107 * - bullet 108 * * bullet 109 * ** bullet 110 * ** bullet 111 * *** bullet 112 * *** bullet 113 * **** bullet 114 * **** bullet 115 * ***** bullet 116 * ***** bullet 117 * **** bullet 118 * *** bullet 119 * ** bullet 120 * * bullet 121 * -- 122 * + 123 * -- 124 * .Numbered 125 * . bullet 126 * . bullet 127 * .. bullet 128 * .. bullet 129 * . bullet 130 * .. bullet 131 * ... bullet 132 * ... bullet 133 * .... bullet 134 * .... bullet 135 * ... bullet 136 * ... bullet 137 * .. bullet 138 * .. bullet 139 * . bullet 140 * -- 141 * <p> 142 * Tables:: 143 * + 144 * .An example table 145 * |=== 146 * |Column 1 |Column 2 |Column 3 147 * <p> 148 * |1 149 * |Item 1 150 * |a 151 * <p> 152 * |2 153 * |Item 2 154 * |b 155 * <p> 156 * |3 157 * |Item 3 158 * |c 159 * |=== 160 * <p> 161 * Sidebar block:: 162 * + 163 * .Optional Title 164 * **** 165 * Usage: Notes in a sidebar, naturally. 166 * **** 167 * <p> 168 * Admonitions:: 169 * + 170 * IMPORTANT: Check this out! 171 * @serial (or @ serialField or @ serialData) 172 * @see Asciidoclet 173 * @since 0.1.0 174 */ 175public class Asciidoclet implements Doclet { 176 177 private StandardDoclet standardDoclet; 178 private DocletOptions docletOptions; 179 private Stylesheets stylesheets; 180 private Reporter reporter; 181 182 /** 183 * Creates a new {@link Asciidoclet} object. 184 */ 185 public Asciidoclet() { 186 standardDoclet = new StandardDoclet(); 187 } 188 189 @Override 190 public void init(Locale locale, Reporter reporter) { 191 this.reporter = reporter; 192 this.standardDoclet.init(locale, reporter); 193 this.docletOptions = new DocletOptions(reporter); 194 this.stylesheets = new Stylesheets(reporter); 195 } 196 197 @Override 198 public String getName() { 199 return "Asciidoclet"; 200 } 201 202 @Override 203 public Set<? extends Option> getSupportedOptions() { 204 Set<Option> options = new HashSet<>(standardDoclet.getSupportedOptions()); 205 Arrays.stream(AsciidocletOptions.values()).map(o -> new OptionProcessor(o, docletOptions)).forEach(options::add); 206 return options; 207 } 208 209 @Override 210 public SourceVersion getSupportedSourceVersion() { 211 return SourceVersion.RELEASE_11; 212 } 213 214 @Override 215 public boolean run(DocletEnvironment environment) { 216 docletOptions.validateOptions(); 217 AsciidoctorConverter converter = new AsciidoctorConverter(docletOptions, reporter); 218 boolean result; 219 try (AsciidoctorFilteredEnvironment env = new AsciidoctorFilteredEnvironment(environment, converter)) { 220 result = standardDoclet.run(env); 221 } catch (IOException e) { 222 throw new UncheckedIOException(e); 223 } 224 return result && postProcess(environment); 225 } 226 227 private boolean postProcess(DocletEnvironment environment) { 228 if (docletOptions.stylesheet().isPresent()) { 229 return true; 230 } 231 return stylesheets.copy(environment); 232 } 233}