diff --git a/.travis.yml b/.travis.yml index 7a6bfbd..9567eef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,6 @@ dist: trusty language: java jdk: - - oraclejdk8 - - openjdk8 - - openjdk7 + - openjdk11 notifications: irc: "irc.freenode.org#asciidoctor" diff --git a/README.adoc b/README.adoc index 32deebc..c395ff5 100644 --- a/README.adoc +++ b/README.adoc @@ -107,7 +107,7 @@ The result is readable source and beautifully rendered Javadocs, the best of bot // tag::usage[] == Usage -Run Javadoc with the `org.asciidoctor.Asciidoclet` doclet class. +Run Javadoc with the `org.asciidoctor.asciidoclet.Asciidoclet` doclet class. Some examples for common build systems are shown below. See <> for supported options. @@ -122,8 +122,12 @@ Asciidoclet may be used via a `maven-javadoc-plugin` doclet: maven-javadoc-plugin 2.9 - 1.7 - org.asciidoctor.Asciidoclet + 11 + + -J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED // <1> + -Xdoclint:all,-html,-accessibility // <2> + + org.asciidoctor.asciidoclet.Asciidoclet org.asciidoctor asciidoclet @@ -139,6 +143,10 @@ Asciidoclet may be used via a `maven-javadoc-plugin` doclet: ---- +<1> For the asciidoclet to work, it needs access to the internals of the `javadoc` tool. +This incantation makes that access possible on moduler JDKs. +<2> Asciidoctor may generate HTML that produces doclint errors, which can cause the build to fail. +To work around that, we have to disable these doclint categories. === Gradle @@ -156,13 +164,13 @@ dependencies { javadoc { options.docletpath = configurations.asciidoclet.files.asType(List) - options.doclet = 'org.asciidoctor.Asciidoclet' + options.doclet = 'org.asciidoctor.asciidoclet.Asciidoclet' options.overview = "src/main/java/overview.adoc" options.addStringOption "-base-dir", "${projectDir}" // <1> options.addStringOption "-attribute", // <2> "name=${project.name}," + "version=${project.version}," + - "title-link=http://example.com[${project.name} ${project.version}]") + "title-link=http://example.com[${project.name} ${project.version}]" } ---- <1> Option names passed to Gradle's `javadoc` task must omit the leading "-", so here "-base-dir" means "--base-dir". @@ -179,7 +187,7 @@ Asciidoclet may be used via a doclet element in Ant's `javadoc` task: - + diff --git a/pom.xml b/pom.xml index a4f0e21..cb2a0f4 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.asciidoctor asciidoclet jar - 1.5.7-SNAPSHOT + 2.0.0-SNAPSHOT AsciiDoc Javadoc Doclet @@ -46,70 +46,69 @@ asciidoctorj 1.5.8.1 - - com.sun.tools - tools - ${java.version} - system - ${java.home}/../lib/tools.jar - - - org.slf4j - slf4j-simple - 1.7.25 - - - com.google.guava - guava - 20.0 - junit junit 4.12 test - - org.mockito - mockito-all - 1.10.19 - test - - - org.powermock - powermock-module-junit4 - 1.6.4 - test - - - org.powermock - powermock-api-mockito - 1.6.4 - test - - - org.hamcrest - hamcrest-library - 1.3 - test - + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M2 + + + enforce-maven + + enforce + + + + + 3.0.5 + + + + + + org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.8.0 + + 11 + 11 + + --add-exports + jdk.javadoc/jdk.javadoc.internal.tool=asciidoclet + --add-exports + jdk.compiler/com.sun.tools.javac.parser=asciidoclet + --add-exports + jdk.compiler/com.sun.tools.javac.tree=asciidoclet + --add-exports + jdk.compiler/com.sun.tools.javac.model=asciidoclet + + + + + org.apache.maven.plugins + maven-surefire-plugin - 1.6 - 1.6 + once + + --add-exports jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED + org.apache.maven.plugins maven-source-plugin - 2.2.1 + 3.0.1 attach-sources @@ -119,11 +118,10 @@ - org.apache.maven.plugins maven-javadoc-plugin - 2.9 + 3.0.1 attach-javadocs @@ -133,28 +131,38 @@ - 1.7 - org.asciidoctor.Asciidoclet + 11 + + --add-exports=jdk.javadoc/jdk.javadoc.internal.tool=asciidoclet + --add-exports=jdk.compiler/com.sun.tools.javac.parser=asciidoclet + --add-exports=jdk.compiler/com.sun.tools.javac.tree=asciidoclet + --add-exports=jdk.compiler/com.sun.tools.javac.model=asciidoclet + -J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED + -Xdoclint:all,-html,-accessibility + + org.asciidoctor.asciidoclet.Asciidoclet - org.asciidoctor - asciidoclet + ${project.groupId} + ${project.artifactId} ${project.version} - + --base-dir ${project.basedir} --attribute "project_name=${project.name}" --attribute "project_version=${project.version}" --attribute "project_desc=${project.description}" - + true - src/main/java/overview.adoc + src/main/java/overview.adoc - com.mycila.maven-license-plugin maven-license-plugin - 1.9.0 + 1.10.b1
NOTICE
@@ -173,12 +181,15 @@ true true + + SLASHSTAR_STYLE +
org.apache.maven.plugins maven-shade-plugin - 3.1.1 + 3.2.1 true shaded diff --git a/src/main/java/org/asciidoctor/asciidoclet/DocletRenderer.java b/src/main/java/module-info.java similarity index 69% rename from src/main/java/org/asciidoctor/asciidoclet/DocletRenderer.java rename to src/main/java/module-info.java index 1dccf83..f0710ac 100644 --- a/src/main/java/org/asciidoctor/asciidoclet/DocletRenderer.java +++ b/src/main/java/module-info.java @@ -1,5 +1,5 @@ -/** - * Copyright 2013-2015 John Ericksen +/* + * Copyright 2013-2018 John Ericksen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,16 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.asciidoctor.asciidoclet; - -import com.sun.javadoc.Doc; - -/** - * Interface used to render a Javadoc Doc - * - * @author John Ericksen - */ -public interface DocletRenderer { - - void renderDoc(Doc doc); -} +module asciidoclet { + requires java.base; + requires jdk.javadoc; + requires asciidoctorj; + exports org.asciidoctor.asciidoclet; +} \ No newline at end of file diff --git a/src/main/java/org/asciidoctor/Asciidoclet.java b/src/main/java/org/asciidoctor/Asciidoclet.java deleted file mode 100644 index 513557f..0000000 --- a/src/main/java/org/asciidoctor/Asciidoclet.java +++ /dev/null @@ -1,288 +0,0 @@ -/** - * Copyright 2013-2015 John Ericksen - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.asciidoctor; - -import com.sun.javadoc.DocErrorReporter; -import com.sun.javadoc.Doclet; -import com.sun.javadoc.LanguageVersion; -import com.sun.javadoc.RootDoc; -import org.asciidoctor.asciidoclet.*; - -/** - * = Asciidoclet - * - * https://github.com/asciidoctor/asciidoclet[Asciidoclet] is a Javadoc Doclet - * that uses http://asciidoctor.org[Asciidoctor] (via the - * https://github.com/asciidoctor/asciidoctorj[Asciidoctor Java integration]) - * to interpet http://asciidoc.org[AsciiDoc] markup within Javadoc comments. - * - * include::README.adoc[tags=usage] - * - * == Examples - * - * Custom attributes:: - * `+{project_name}+`;; {project_name} - * `+{project_desc}+`;; {project_desc} - * `+{project_version}+`;; {project_version} - * - * Code block (with syntax highlighting added by CodeRay):: - * + - * [source,java] - * -- - * /** - * * = Asciidoclet - * * - * * A Javadoc Doclet that uses http://asciidoctor.org[Asciidoctor] - * * to render http://asciidoc.org[AsciiDoc] markup in Javadoc comments. - * * - * * @author https://github.com/johncarl81[John Ericksen] - * *\/ - * public class Asciidoclet extends Doclet { - * private final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); // <1> - * - * @SuppressWarnings("UnusedDeclaration") - * public static boolean start(RootDoc rootDoc) { - * new Asciidoclet().render(rootDoc); // <2> - * return Standard.start(rootDoc); - * } - * } - * -- - * <1> Creates an instance of the Asciidoctor Java integration - * <2> Runs Javadoc comment strings through Asciidoctor - * - * Inline code:: `code()` - * - * Headings:: - * + - * -- - * [float] - * = Heading 1 - * - * [float] - * == Heading 2 - * - * [float] - * === Heading 3 - * - * [float] - * ==== Heading 4 - * - * [float] - * ===== Heading 5 - * -- - * - * Links:: - * Doc Writer + - * http://asciidoc.org[AsciiDoc] is a lightweight markup language. + - * Learn more about it at http://asciidoctor.org. + - * - * Bullets:: - * + - * -- - * .Unnumbered - * * bullet - * * bullet - * - bullet - * - bullet - * * bullet - * ** bullet - * ** bullet - * *** bullet - * *** bullet - * **** bullet - * **** bullet - * ***** bullet - * ***** bullet - * **** bullet - * *** bullet - * ** bullet - * * bullet - * -- - * + - * -- - * .Numbered - * . bullet - * . bullet - * .. bullet - * .. bullet - * . bullet - * .. bullet - * ... bullet - * ... bullet - * .... bullet - * .... bullet - * ... bullet - * ... bullet - * .. bullet - * .. bullet - * . bullet - * -- - * - * Tables:: - * + - * .An example table - * |=== - * |Column 1 |Column 2 |Column 3 - * - * |1 - * |Item 1 - * |a - * - * |2 - * |Item 2 - * |b - * - * |3 - * |Item 3 - * |c - * |=== - * - * Sidebar block:: - * + - * .Optional Title - * **** - * Usage: Notes in a sidebar, naturally. - * **** - * - * Admonitions:: - * + - * IMPORTANT: Check this out! - * - * @author https://github.com/johncarl81[John Ericksen] - * @version {project_version} - * @see org.asciidoctor.Asciidoclet - * @since 0.1.0 - * @serial (or @serialField or @serialData) - */ -public class Asciidoclet extends Doclet { - - private final RootDoc rootDoc; - private final DocletOptions docletOptions; - private final DocletIterator iterator; - private final Stylesheets stylesheets; - - public Asciidoclet(RootDoc rootDoc) { - this.rootDoc = rootDoc; - this.docletOptions = new DocletOptions(rootDoc); - this.iterator = new DocletIterator(docletOptions); - this.stylesheets = new Stylesheets(docletOptions, rootDoc); - } - - // test use - Asciidoclet(RootDoc rootDoc, DocletIterator iterator, Stylesheets stylesheets) { - this.rootDoc = rootDoc; - this.docletOptions = new DocletOptions(rootDoc); - this.iterator = iterator; - this.stylesheets = stylesheets; - } - - /** - * .Example usage - * [source,java] - * exampleDeprecated("do not use"); - * - * @deprecated for example purposes - * @exception Exception example - * @throws RuntimeException example - * @serialData something else - * @link Asciidoclet - */ - public static void exampleDeprecated(String field) throws Exception { - //noop - } - - /** - * Sets the language version to Java 5. - * - * _Javadoc spec requirement._ - * - * @return language version number - */ - @SuppressWarnings("UnusedDeclaration") - public static LanguageVersion languageVersion() { - return LanguageVersion.JAVA_1_5; - } - - /** - * Sets the option length to the standard Javadoc option length. - * - * _Javadoc spec requirement._ - * - * @param option input option - * @return length of required parameters - */ - @SuppressWarnings("UnusedDeclaration") - public static int optionLength(String option) { - return optionLength(option, new StandardAdapter()); - } - - /** - * The starting point of Javadoc render. - * - * _Javadoc spec requirement._ - * - * @param rootDoc input class documents - * @return success - */ - @SuppressWarnings("UnusedDeclaration") - public static boolean start(RootDoc rootDoc) { - return new Asciidoclet(rootDoc).start(new StandardAdapter()); - } - - /** - * Processes the input options by delegating to the standard handler. - * - * _Javadoc spec requirement._ - * - * @param options input option array - * @param errorReporter error handling - * @return success - */ - @SuppressWarnings("UnusedDeclaration") - public static boolean validOptions(String[][] options, DocErrorReporter errorReporter) { - return validOptions(options, errorReporter, new StandardAdapter()); - } - - static int optionLength(String option, StandardAdapter standardDoclet) { - return DocletOptions.optionLength(option, standardDoclet); - } - - static boolean validOptions(String[][] options, DocErrorReporter errorReporter, StandardAdapter standardDoclet) { - return DocletOptions.validOptions(options, errorReporter, standardDoclet); - } - - boolean start(StandardAdapter standardDoclet) { - return run(standardDoclet) - && postProcess(); - } - - private boolean run(StandardAdapter standardDoclet) { - AsciidoctorRenderer renderer = new AsciidoctorRenderer(docletOptions, rootDoc); - try { - return iterator.render(rootDoc, renderer) && - standardDoclet.start(rootDoc); - } finally { - renderer.cleanup(); - } - } - - private boolean postProcess() { - if (docletOptions.stylesheet().isPresent()) { - return true; - } - return stylesheets.copy(); - } -} diff --git a/src/main/java/org/asciidoctor/asciidoclet/AsciiDocTrees.java b/src/main/java/org/asciidoctor/asciidoclet/AsciiDocTrees.java new file mode 100644 index 0000000..2530d39 --- /dev/null +++ b/src/main/java/org/asciidoctor/asciidoclet/AsciiDocTrees.java @@ -0,0 +1,275 @@ +/* + * Copyright 2013-2018 John Ericksen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.asciidoctor.asciidoclet; + +import com.sun.source.doctree.DocCommentTree; +import com.sun.source.doctree.DocTree; +import com.sun.source.tree.CatchTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.Scope; +import com.sun.source.tree.Tree; +import com.sun.source.util.DocSourcePositions; +import com.sun.source.util.DocTreeFactory; +import com.sun.source.util.DocTreePath; +import com.sun.source.util.DocTrees; +import com.sun.source.util.TreePath; +import com.sun.tools.javac.model.JavacElements; +import com.sun.tools.javac.parser.Tokens; +import com.sun.tools.javac.tree.JCTree; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Field; +import java.text.BreakIterator; +import java.util.List; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ErrorType; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.JavaFileManager; +import javax.tools.StandardJavaFileManager; + +import static javax.tools.StandardLocation.SOURCE_PATH; + +class AsciiDocTrees extends DocTrees +{ + private final AsciidoctorRenderer renderer; + private final StandardJavaFileManager fileManager; + private final DocTrees docTrees; + private final Field elementsField; + + AsciiDocTrees( AsciidoctorRenderer renderer, StandardJavaFileManager fileManager, DocTrees docTrees ) + { + this.renderer = renderer; + this.fileManager = fileManager; + this.docTrees = docTrees; + try + { + this.elementsField = docTrees.getClass().getDeclaredField( "elements" ); + this.elementsField.setAccessible( true ); + } + catch ( Exception e ) + { + throw new RuntimeException( e ); + } + } + + public BreakIterator getBreakIterator() + { + return docTrees.getBreakIterator(); + } + + public String getDocComment( TreePath path ) + { + return renderer.renderDoc( docTrees.getDocComment( path ) ); + } + + public DocCommentTree getDocCommentTree( TreePath path ) + { + // First we convert the asciidoctor to HTML inside the AST. + JCTree.JCCompilationUnit cu = (JCTree.JCCompilationUnit) path.getCompilationUnit(); + LazyDocCommentTableProcessor.processComments( cu.docComments, this::convertToAsciidoctor ); + + // Then we allow the normal javadoc parsing to continue on the asciidoctor result. + return docTrees.getDocCommentTree( path ); + } + + private Tokens.Comment convertToAsciidoctor( Tokens.Comment comment ) + { + String javadoc = comment.getText(); + String asciidoc = renderer.renderDoc( javadoc ); + AsciidocComment result = new AsciidocComment( asciidoc, comment );System.err.println( "" ); + return result; + } + + public DocCommentTree getDocCommentTree( Element e ) + { + TreePath path = getPath( e ); + if ( path == null ) + { + return null; + } + return getDocCommentTree( path ); + } + + public DocCommentTree getDocCommentTree( FileObject fileObject ) + { + // Empty names are used for built-in headers and footers, which need no asciidoctor processing anyway. + if ( !fileObject.getName().isEmpty() && !(fileObject instanceof AsciidocFileView)) + { + return docTrees.getDocCommentTree( new AsciidocFileView( renderer, fileObject ) ); + } + return docTrees.getDocCommentTree( fileObject ); + } + + public DocCommentTree getDocCommentTree( Element e, String relativePath ) throws IOException + { + PackageElement pkg = getElements().getPackageOf( e ); + JavaFileManager fileManager = getFileManager(); + FileObject input = fileManager.getFileForInput( SOURCE_PATH, pkg.getQualifiedName().toString(), relativePath ); + if ( input == null ) + { + throw new FileNotFoundException( relativePath ); + } + return getDocCommentTree( input ); + } + + private JavacElements getElements() + { + try + { + return (JavacElements) elementsField.get( docTrees ); + } + catch ( Exception e ) + { + throw new RuntimeException( e ); + } + } + + private JavaFileManager getFileManager() + { + return fileManager; + } + + public DocTreePath getDocTreePath( FileObject fileObject, PackageElement packageElement ) + { + return docTrees.getDocTreePath( fileObject, packageElement ); + } + + public Element getElement( DocTreePath path ) + { + return docTrees.getElement( path ); + } + + public List getFirstSentence( List list ) + { + return docTrees.getFirstSentence( list ); + } + + public DocSourcePositions getSourcePositions() + { + return docTrees.getSourcePositions(); + } + + public void printMessage( Diagnostic.Kind kind, CharSequence msg, DocTree t, DocCommentTree c, CompilationUnitTree root ) + { + docTrees.printMessage( kind, msg, t, c, root ); + } + + public void setBreakIterator( BreakIterator breakiterator ) + { + docTrees.setBreakIterator( breakiterator ); + } + + public DocTreeFactory getDocTreeFactory() + { + return docTrees.getDocTreeFactory(); + } + + public Tree getTree( Element element ) + { + return docTrees.getTree( element ); + } + + public ClassTree getTree( TypeElement element ) + { + return docTrees.getTree( element ); + } + + public MethodTree getTree( ExecutableElement method ) + { + return docTrees.getTree( method ); + } + + public Tree getTree( Element e, AnnotationMirror a ) + { + return docTrees.getTree( e, a ); + } + + public Tree getTree( Element e, AnnotationMirror a, AnnotationValue v ) + { + return docTrees.getTree( e, a, v ); + } + + public TreePath getPath( CompilationUnitTree unit, Tree node ) + { + return docTrees.getPath( unit, node ); + } + + public TreePath getPath( Element e ) + { + return docTrees.getPath( e ); + } + + public TreePath getPath( Element e, AnnotationMirror a ) + { + return docTrees.getPath( e, a ); + } + + public TreePath getPath( Element e, AnnotationMirror a, AnnotationValue v ) + { + return docTrees.getPath( e, a, v ); + } + + public Element getElement( TreePath path ) + { + return docTrees.getElement( path ); + } + + public TypeMirror getTypeMirror( TreePath path ) + { + return docTrees.getTypeMirror( path ); + } + + public Scope getScope( TreePath path ) + { + return docTrees.getScope( path ); + } + + public boolean isAccessible( Scope scope, TypeElement type ) + { + return docTrees.isAccessible( scope, type ); + } + + public boolean isAccessible( Scope scope, Element member, DeclaredType type ) + { + return docTrees.isAccessible( scope, member, type ); + } + + public TypeMirror getOriginalType( ErrorType errorType ) + { + return docTrees.getOriginalType( errorType ); + } + + public void printMessage( Diagnostic.Kind kind, CharSequence msg, Tree t, CompilationUnitTree root ) + { + docTrees.printMessage( kind, msg, t, root ); + } + + public TypeMirror getLub( CatchTree tree ) + { + return docTrees.getLub( tree ); + } +} diff --git a/src/main/java/org/asciidoctor/asciidoclet/AsciidocComment.java b/src/main/java/org/asciidoctor/asciidoclet/AsciidocComment.java new file mode 100644 index 0000000..fb09e4f --- /dev/null +++ b/src/main/java/org/asciidoctor/asciidoclet/AsciidocComment.java @@ -0,0 +1,55 @@ +/* + * Copyright 2013-2018 John Ericksen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.asciidoctor.asciidoclet; + +import com.sun.tools.javac.parser.Tokens; + +class AsciidocComment implements Tokens.Comment +{ + private final String asciidoc; + private final Tokens.Comment comment; + + AsciidocComment( String asciidoc, Tokens.Comment comment ) + { + this.asciidoc = asciidoc; + this.comment = comment; + } + + @Override + public String getText() + { + return asciidoc; + } + + @Override + public int getSourcePos( int index ) + { + // can we somehow map positions in the asciidoctor back to positions in the source javadoc? + return comment.getSourcePos( 0 ); + } + + @Override + public CommentStyle getStyle() + { + return comment.getStyle(); + } + + @Override + public boolean isDeprecated() + { + return comment.isDeprecated(); + } +} diff --git a/src/main/java/org/asciidoctor/asciidoclet/AsciidocFileView.java b/src/main/java/org/asciidoctor/asciidoclet/AsciidocFileView.java new file mode 100644 index 0000000..83e86df --- /dev/null +++ b/src/main/java/org/asciidoctor/asciidoclet/AsciidocFileView.java @@ -0,0 +1,159 @@ +/* + * Copyright 2013-2018 John Ericksen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.asciidoctor.asciidoclet; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.Writer; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.Charset; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; +import javax.tools.FileObject; +import javax.tools.JavaFileObject; + +class AsciidocFileView implements JavaFileObject +{ + private final AsciidoctorRenderer renderer; + private final FileObject fileObject; + private String renderedContents; + + AsciidocFileView( AsciidoctorRenderer renderer, FileObject fileObject ) + { + this.renderer = renderer; + this.fileObject = fileObject; + } + + @Override + public URI toUri() + { + try + { + URI uri = fileObject.toUri(); + uri = new URI( maskFileExtension( uri.toString() ) ); + return uri; + } + catch ( URISyntaxException e ) + { + throw new RuntimeException( e ); + } + } + + @Override + public String getName() + { + return maskFileExtension( fileObject.getName() ); + } + + private String maskFileExtension( String name ) + { + if ( isAsciidoctorFile( name ) ) + { + name = name.substring( 0, name.lastIndexOf( '.' ) ) + ".html"; + } + return name; + } + + private boolean isAsciidoctorFile( String name ) + { + return name.endsWith( ".adoc" ) || name.endsWith( ".ad" ) || name.endsWith( ".asciidoc" ) || name.endsWith( ".txt" ); + } + + @Override + public InputStream openInputStream() throws IOException + { + return new ByteArrayInputStream( getCharContent( true ).getBytes( Charset.defaultCharset() ) ); + } + + @Override + public OutputStream openOutputStream() throws IOException + { + return fileObject.openOutputStream(); + } + + @Override + public Reader openReader( boolean ignoreEncodingErrors ) throws IOException + { + return new StringReader( getCharContent( ignoreEncodingErrors ) ); + } + + @Override + public String getCharContent( boolean ignoreEncodingErrors ) throws IOException + { + if ( renderedContents == null ) + { + renderedContents = fileObject.getCharContent( ignoreEncodingErrors ).toString(); + if ( isAsciidoctorFile( fileObject.getName() ) ) + { + renderedContents = "" + renderer.renderDoc( renderedContents ) + ""; + } + } + return renderedContents; + } + + @Override + public Writer openWriter() throws IOException + { + return fileObject.openWriter(); + } + + @Override + public long getLastModified() + { + return fileObject.getLastModified(); + } + + @Override + public boolean delete() + { + return fileObject.delete(); + } + + @Override + public Kind getKind() + { + return ((JavaFileObject) fileObject).getKind(); + } + + @Override + public boolean isNameCompatible( String simpleName, Kind kind ) + { + return ((JavaFileObject) fileObject).isNameCompatible( simpleName, kind ); + } + + @Override + public NestingKind getNestingKind() + { + return ((JavaFileObject) fileObject).getNestingKind(); + } + + @Override + public Modifier getAccessLevel() + { + return ((JavaFileObject) fileObject).getAccessLevel(); + } + + @SuppressWarnings( "unchecked" ) + T unwrap() + { + return (T) fileObject; + } +} diff --git a/src/main/java/org/asciidoctor/asciidoclet/Asciidoclet.java b/src/main/java/org/asciidoctor/asciidoclet/Asciidoclet.java new file mode 100644 index 0000000..f9b7e76 --- /dev/null +++ b/src/main/java/org/asciidoctor/asciidoclet/Asciidoclet.java @@ -0,0 +1,241 @@ +/* + * Copyright 2013-2018 John Ericksen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.asciidoctor.asciidoclet; + +import jdk.javadoc.doclet.Doclet; +import jdk.javadoc.doclet.DocletEnvironment; +import jdk.javadoc.doclet.Reporter; +import jdk.javadoc.doclet.StandardDoclet; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import javax.lang.model.SourceVersion; + +/** + * = Asciidoclet + * + * https://github.com/asciidoctor/asciidoclet[Asciidoclet] is a Javadoc Doclet + * that uses http://asciidoctor.org[Asciidoctor] (via the + * https://github.com/asciidoctor/asciidoctorj[Asciidoctor Java integration]) + * to interpet http://asciidoc.org[AsciiDoc] markup within Javadoc comments. + * + * include::README.adoc[tags=usage] + * + * == Examples + * + * Custom attributes:: + * `+{project_name}+`;; {project_name} + * `+{project_desc}+`;; {project_desc} + * `+{project_version}+`;; {project_version} + * + * Code block (with syntax highlighting added by CodeRay):: + * + + * [source,java] + * -- + * /** + * * = Asciidoclet + * * + * * A Javadoc Doclet that uses http://asciidoctor.org[Asciidoctor] + * * to render http://asciidoc.org[AsciiDoc] markup in Javadoc comments. + * * + * * @author https://github.com/johncarl81[John Ericksen] + * *\/ + * public class Asciidoclet extends Doclet { + * private final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); // <1> + * + * @SuppressWarnings("UnusedDeclaration") + * public static boolean start(RootDoc rootDoc) { + * new Asciidoclet().render(rootDoc); // <2> + * return Standard.start(rootDoc); + * } + * } + * -- + * <1> Creates an instance of the Asciidoctor Java integration + * <2> Runs Javadoc comment strings through Asciidoctor + * + * Inline code:: `code()` + * + * Headings:: + * + + * -- + * [float] + * = Heading 1 + * + * [float] + * == Heading 2 + * + * [float] + * === Heading 3 + * + * [float] + * ==== Heading 4 + * + * [float] + * ===== Heading 5 + * -- + * + * Links:: + * Doc Writer + + * http://asciidoc.org[AsciiDoc] is a lightweight markup language. + + * Learn more about it at http://asciidoctor.org. + + * + * Bullets:: + * + + * -- + * .Unnumbered + * * bullet + * * bullet + * - bullet + * - bullet + * * bullet + * ** bullet + * ** bullet + * *** bullet + * *** bullet + * **** bullet + * **** bullet + * ***** bullet + * ***** bullet + * **** bullet + * *** bullet + * ** bullet + * * bullet + * -- + * + + * -- + * .Numbered + * . bullet + * . bullet + * .. bullet + * .. bullet + * . bullet + * .. bullet + * ... bullet + * ... bullet + * .... bullet + * .... bullet + * ... bullet + * ... bullet + * .. bullet + * .. bullet + * . bullet + * -- + * + * Tables:: + * + + * .An example table + * |=== + * |Column 1 |Column 2 |Column 3 + * + * |1 + * |Item 1 + * |a + * + * |2 + * |Item 2 + * |b + * + * |3 + * |Item 3 + * |c + * |=== + * + * Sidebar block:: + * + + * .Optional Title + * **** + * Usage: Notes in a sidebar, naturally. + * **** + * + * Admonitions:: + * + + * IMPORTANT: Check this out! + * + * @author https://github.com/johncarl81[John Ericksen] + * @version {project_version} + * @see Asciidoclet + * @since 0.1.0 + * @serial (or @serialField or @serialData) + */ +public class Asciidoclet implements Doclet +{ + + private StandardDoclet standardDoclet; + private DocletOptions docletOptions; + private Stylesheets stylesheets; + private Reporter reporter; + + public Asciidoclet() { + standardDoclet = new StandardDoclet(); + } + + @Override + public void init( Locale locale, Reporter reporter ) + { + this.reporter = reporter; + standardDoclet.init( locale, reporter ); + this.docletOptions = new DocletOptions( reporter ); + this.stylesheets = new Stylesheets( reporter ); + } + + @Override + public String getName() + { + return "Asciidoclet"; + } + + @Override + public Set getSupportedOptions() + { + Set