001/**
002 * Copyright 2013-2015 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 *    http://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;
017
018import com.sun.javadoc.DocErrorReporter;
019import com.sun.javadoc.Doclet;
020import com.sun.javadoc.LanguageVersion;
021import com.sun.javadoc.RootDoc;
022import org.asciidoctor.asciidoclet.*;
023
024/**
025 * = Asciidoclet
026 *
027 * https://github.com/asciidoctor/asciidoclet[Asciidoclet] is a Javadoc Doclet
028 * that uses http://asciidoctor.org[Asciidoctor] (via the
029 * https://github.com/asciidoctor/asciidoctorj[Asciidoctor Java integration])
030 * to interpet http://asciidoc.org[AsciiDoc] markup within Javadoc comments.
031 *
032 * include::README.adoc[tags=usage]
033 *
034 * == Examples
035 *
036 * Custom attributes::
037 * `+{project_name}+`;; {project_name}
038 * `+{project_desc}+`;; {project_desc}
039 * `+{project_version}+`;; {project_version}
040 *
041 * Code block (with syntax highlighting added by CodeRay)::
042 * +
043 * [source,java]
044 * --
045 * /**
046 *  * = Asciidoclet
047 *  *
048 *  * A Javadoc Doclet that uses http://asciidoctor.org[Asciidoctor]
049 *  * to render http://asciidoc.org[AsciiDoc] markup in Javadoc comments.
050 *  *
051 *  * @author https://github.com/johncarl81[John Ericksen]
052 *  *\/
053 * public class Asciidoclet extends Doclet {
054 *     private final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); // <1>
055 *
056 *     @SuppressWarnings("UnusedDeclaration")
057 *     public static boolean start(RootDoc rootDoc) {
058 *         new Asciidoclet().render(rootDoc); // <2>
059 *         return Standard.start(rootDoc);
060 *     }
061 * }
062 * --
063 * <1> Creates an instance of the Asciidoctor Java integration
064 * <2> Runs Javadoc comment strings through Asciidoctor
065 *
066 * Inline code:: `code()`
067 *
068 * Headings::
069 * +
070 * --
071 * [float]
072 * = Heading 1
073 *
074 * [float]
075 * == Heading 2
076 *
077 * [float]
078 * === Heading 3
079 *
080 * [float]
081 * ==== Heading 4
082 *
083 * [float]
084 * ===== Heading 5
085 * --
086 *
087 * Links::
088 * Doc Writer <doc@example.com> +
089 * http://asciidoc.org[AsciiDoc] is a lightweight markup language. +
090 * Learn more about it at http://asciidoctor.org. +
091 *
092 * Bullets::
093 * +
094 * --
095 * .Unnumbered
096 * * bullet
097 * * bullet
098 * - bullet
099 * - bullet
100 * * bullet
101 * ** bullet
102 * ** bullet
103 * *** bullet
104 * *** bullet
105 * **** bullet
106 * **** bullet
107 * ***** bullet
108 * ***** bullet
109 * **** bullet
110 * *** bullet
111 * ** bullet
112 * * bullet
113 * --
114 * +
115 * --
116 * .Numbered
117 * . bullet
118 * . bullet
119 * .. bullet
120 * .. bullet
121 * . bullet
122 * .. bullet
123 * ... bullet
124 * ... bullet
125 * .... bullet
126 * .... bullet
127 * ... bullet
128 * ... bullet
129 * .. bullet
130 * .. bullet
131 * . bullet
132 * --
133 *
134 * Tables::
135 * +
136 * .An example table
137 * |===
138 * |Column 1 |Column 2 |Column 3
139 * 
140 * |1
141 * |Item 1
142 * |a
143 * 
144 * |2
145 * |Item 2
146 * |b
147 * 
148 * |3
149 * |Item 3
150 * |c
151 * |===
152 *
153 * Sidebar block::
154 * +
155 * .Optional Title
156 * ****
157 * Usage: Notes in a sidebar, naturally.
158 * ****
159 *
160 * Admonitions::
161 * +
162 * IMPORTANT: Check this out!
163 *
164 * @author https://github.com/johncarl81[John Ericksen]
165 * @version {project_version}
166 * @see org.asciidoctor.Asciidoclet
167 * @since 0.1.0
168 * @serial (or @serialField or @serialData)
169 */
170public class Asciidoclet extends Doclet {
171
172    private final RootDoc rootDoc;
173    private final DocletOptions docletOptions;
174    private final DocletIterator iterator;
175    private final Stylesheets stylesheets;
176
177    public Asciidoclet(RootDoc rootDoc) {
178        this.rootDoc = rootDoc;
179        this.docletOptions = new DocletOptions(rootDoc);
180        this.iterator = new DocletIterator(docletOptions);
181        this.stylesheets = new Stylesheets(docletOptions, rootDoc);
182    }
183
184    // test use
185    Asciidoclet(RootDoc rootDoc, DocletIterator iterator, Stylesheets stylesheets) {
186        this.rootDoc = rootDoc;
187        this.docletOptions = new DocletOptions(rootDoc);
188        this.iterator = iterator;
189        this.stylesheets = stylesheets;
190    }
191
192    /**
193     * .Example usage
194     * [source,java]
195     * exampleDeprecated("do not use");
196     *
197     * @deprecated for example purposes
198     * @exception Exception example
199     * @throws RuntimeException example
200     * @serialData something else
201     * @link Asciidoclet
202     */
203    public static void exampleDeprecated(String field) throws Exception {
204        //noop
205    }
206
207    /**
208     * Sets the language version to Java 5.
209     *
210     * _Javadoc spec requirement._
211     *
212     * @return language version number
213     */
214    @SuppressWarnings("UnusedDeclaration")
215    public static LanguageVersion languageVersion() {
216        return LanguageVersion.JAVA_1_5;
217    }
218
219    /**
220     * Sets the option length to the standard Javadoc option length.
221     *
222     * _Javadoc spec requirement._
223     *
224     * @param option input option
225     * @return length of required parameters
226     */
227    @SuppressWarnings("UnusedDeclaration")
228    public static int optionLength(String option) {
229        return optionLength(option, new StandardAdapter());
230    }
231
232    /**
233     * The starting point of Javadoc render.
234     *
235     * _Javadoc spec requirement._
236     *
237     * @param rootDoc input class documents
238     * @return success
239     */
240    @SuppressWarnings("UnusedDeclaration")
241    public static boolean start(RootDoc rootDoc) {
242        return new Asciidoclet(rootDoc).start(new StandardAdapter());
243    }
244
245    /**
246     * Processes the input options by delegating to the standard handler.
247     *
248     * _Javadoc spec requirement._
249     *
250     * @param options input option array
251     * @param errorReporter error handling
252     * @return success
253     */
254    @SuppressWarnings("UnusedDeclaration")
255    public static boolean validOptions(String[][] options, DocErrorReporter errorReporter) {
256        return validOptions(options, errorReporter, new StandardAdapter());
257    }
258
259    static int optionLength(String option, StandardAdapter standardDoclet) {
260        return DocletOptions.optionLength(option, standardDoclet);
261    }
262
263    static boolean validOptions(String[][] options, DocErrorReporter errorReporter, StandardAdapter standardDoclet) {
264        return DocletOptions.validOptions(options, errorReporter, standardDoclet);
265    }
266
267    boolean start(StandardAdapter standardDoclet) {
268        return run(standardDoclet)
269                && postProcess();
270    }
271
272    private boolean run(StandardAdapter standardDoclet) {
273        AsciidoctorRenderer renderer = new AsciidoctorRenderer(docletOptions, rootDoc);
274        try {
275            return iterator.render(rootDoc, renderer) &&
276                    standardDoclet.start(rootDoc);
277        } finally {
278            renderer.cleanup();
279        }
280    }
281
282    private boolean postProcess() {
283        if (docletOptions.stylesheet().isPresent()) {
284            return true;
285        }
286        return stylesheets.copy();
287    }
288}