├── .github ├── dependabot.yml └── workflows │ ├── ci-development-branch.yml │ ├── ci-maintenance-branch.yml │ └── release.yaml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .sdkmanrc ├── LICENSE ├── NOTICE ├── README.adoc ├── docs ├── antora.yml └── modules │ ├── ROOT │ ├── nav.adoc │ └── pages │ │ ├── additional-features.adoc │ │ ├── getting-started.adoc │ │ ├── index.adoc │ │ ├── options.adoc │ │ └── usage.adoc │ └── project │ ├── nav.adoc │ └── pages │ ├── license.adoc │ ├── powered-by-asciidoclet.adoc │ └── resources.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── docs └── asciidoc │ └── release-process.adoc ├── it ├── java-11 │ └── class-comments │ │ ├── invoker.properties │ │ ├── pom.xml │ │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── example │ │ │ └── StringUtils.java │ │ └── validate.groovy └── java-17 │ └── class-comments │ ├── invoker.properties │ ├── pom.xml │ ├── src │ └── main │ │ └── java │ │ └── example │ │ └── StringUtils.java │ └── validate.groovy ├── main ├── java │ ├── module-info.java │ ├── org │ │ └── asciidoctor │ │ │ └── asciidoclet │ │ │ ├── AntPathMatcher.java │ │ │ ├── AsciiDocTrees.java │ │ │ ├── AsciidocComment.java │ │ │ ├── AsciidocFileView.java │ │ │ ├── Asciidoclet.java │ │ │ ├── AsciidocletOptions.java │ │ │ ├── AsciidoctorConverter.java │ │ │ ├── AsciidoctorFileManager.java │ │ │ ├── AsciidoctorFilteredEnvironment.java │ │ │ ├── AsciidoctorOptionsFactory.java │ │ │ ├── AttributesLoader.java │ │ │ ├── DocletOptions.java │ │ │ ├── JavadocParser.java │ │ │ ├── LazyDocCommentTableProcessor.java │ │ │ ├── OptionProcessor.java │ │ │ ├── OutputTemplates.java │ │ │ ├── Stylesheets.java │ │ │ └── package-info.java │ └── overview.adoc └── resources │ ├── coderay-asciidoctor.css │ ├── stylesheet11.css │ ├── stylesheet17.css │ └── templates │ ├── paragraph.html.haml │ └── section.html.haml └── test └── java └── org └── asciidoctor └── asciidoclet ├── AsciidocletIntegrationTest.java ├── AsciidoctorConverterTest.java ├── AsciidoctorOptionsFactoryTest.java ├── AttributesLoaderTest.java ├── DocletOptionsTest.java ├── JavadocParserTest.java ├── LazyDocCommentTableProcessorTest.java ├── StubReporter.java └── StylesheetsTest.java /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | labels: 8 | - "dependencies" 9 | -------------------------------------------------------------------------------- /.github/workflows/ci-development-branch.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths-ignore: 7 | - LICENCE 8 | - NOTICE 9 | - README.adoc 10 | - docs/** 11 | pull_request: 12 | branches: 13 | - main 14 | paths-ignore: 15 | - LICENCE 16 | - NOTICE 17 | - README.adoc 18 | - docs/** 19 | 20 | jobs: 21 | build: 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | os: 26 | - ubuntu-latest 27 | - windows-latest 28 | - macos-latest 29 | java-version: 30 | - 11 31 | - 17 32 | - 21 33 | runs-on: ${{ matrix.os }} 34 | steps: 35 | - uses: actions/checkout@v4 36 | - name: Set up Java ${{ matrix.java-version }} 37 | uses: actions/setup-java@v4 38 | with: 39 | distribution: 'temurin' 40 | java-version: ${{ matrix.java-version }} 41 | cache: 'maven' 42 | cache-dependency-path: 'pom.xml' 43 | - name: Build & Test 44 | run: mvn -B clean verify -Prun-its 45 | -------------------------------------------------------------------------------- /.github/workflows/ci-maintenance-branch.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - v1.5.x 6 | paths-ignore: 7 | - LICENCE 8 | - NOTICE 9 | - README.adoc 10 | - docs/** 11 | pull_request: 12 | branches: 13 | - v1.5.x 14 | paths-ignore: 15 | - LICENCE 16 | - NOTICE 17 | - README.adoc 18 | - docs/** 19 | 20 | jobs: 21 | build: 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | os: 26 | - ubuntu-latest 27 | - windows-latest 28 | - macos-latest 29 | java-version: 30 | - 8 31 | runs-on: ${{ matrix.os }} 32 | steps: 33 | - uses: actions/checkout@v4 34 | - name: Set up Java ${{ matrix.java-version }} 35 | uses: actions/setup-java@v4 36 | with: 37 | distribution: 'temurin' 38 | java-version: ${{ matrix.java-version }} 39 | cache: 'maven' 40 | cache-dependency-path: 'pom.xml' 41 | - name: Build & Test 42 | run: mvn -B -Prun-its clean verify 43 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: workflow_dispatch 4 | permissions: 5 | contents: write 6 | 7 | jobs: 8 | release: 9 | environment: release 10 | env: 11 | GPG_KEYNAME: ${{ secrets.GPG_KEYNAME }} 12 | GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} 13 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | - name: Setup Java 19 | uses: actions/setup-java@v4 20 | with: 21 | distribution: 'temurin' 22 | java-version: 11 23 | - uses: s4u/maven-settings-action@v3.1.0 24 | with: 25 | servers: | 26 | [{ 27 | "id": "ossrh", 28 | "username": "${{ secrets.OSS_SONATYPE_USERNAME }}", 29 | "password": "${{ secrets.OSS_SONATYPE_PASSWORD }}" 30 | }] 31 | - name: Configure Git user 32 | run: | 33 | git config user.email "actions@github.com" 34 | git config user.name "GitHub Actions" 35 | - name: Configure GPG key 36 | run: echo -e "${{ env.GPG_PRIVATE_KEY }}" | gpg --import --batch 37 | - name: Build artifacts 38 | run: ./mvnw clean verify -B -Prelease -Dmaven.test.skip 39 | - name: Publish artifacts 40 | run: ./mvnw release:prepare release:perform -B -Darguments="-Prelease -Dmaven.test.skip" 41 | - name: Close release 42 | run: | 43 | echo "Release completed 🎉" 44 | echo "Remember to 'Close' & 'Release' at https://oss.sonatype.org" 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.classpath 2 | /.project 3 | /.settings/ 4 | .idea/* 5 | *~ 6 | *.iml 7 | target 8 | tmp 9 | out 10 | dependency-reduced-pom.xml 11 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asciidoctor/asciidoclet/83ae3fab7165d8a4c0dcb0ffbc1e819fece2fca7/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /.sdkmanrc: -------------------------------------------------------------------------------- 1 | # Enable auto-env through the sdkman_auto_env config 2 | # Add key=value pairs of SDKs to use below 3 | java=11.0.22-tem 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright ${startYear}-${currentYear} ${name} 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | https://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Asciidoclet 2 | John Ericksen ; Ben Evans 3 | :description: This is a guide for setting up and using the Asciidoclet project. Asciidoclet is a Javadoc Doclet based on Asciidoctor that lets you write Javadoc in the AsciiDoc syntax. 4 | :keywords: Asciidoclet, AsciiDoc, Asciidoctor, syntax, Javadoc, Doclet, reference 5 | :idprefix: 6 | :idseparator: - 7 | :source-language: java 8 | ifdef::env-browser[] 9 | :sectanchors: 10 | :source-highlighter: highlight.js 11 | :icons: font 12 | endif::[] 13 | ifdef::env-github,env-browser[] 14 | :toc: preamble 15 | endif::[] 16 | ifdef::env-github[] 17 | :badges: 18 | :!toc-title: 19 | endif::[] 20 | :release-version: 1.5.6 21 | // Refs 22 | :asciidoclet-src-ref: https://github.com/asciidoctor/asciidoclet 23 | :asciidoclet-javadoc-ref: https://oss.sonatype.org/service/local/repositories/releases/archive/org/asciidoctor/asciidoclet/1.5.2/asciidoclet-1.5.2-javadoc.jar/!/index.html 24 | :asciidoclet-release-ref: https://asciidoctor.org/news/2014/09/09/asciidoclet-1.5.0-released/ 25 | :asciidoc-ref: https://asciidoc.org 26 | :asciidoctor-java-ref: https://asciidoctor.org/docs/install-and-use-asciidoctor-java-integration/ 27 | :asciidoclet-issues-ref: https://github.com/asciidoctor/asciidoclet/issues 28 | :asciidoctor-src-ref: https://github.com/asciidoctor/asciidoctor 29 | :asciidoctor-java-src-ref: https://github.com/asciidoctor/asciidoctor-java-integration 30 | :discuss-ref: https://chat.asciidoctor.org 31 | 32 | ifdef::badges[] 33 | image:https://img.shields.io/travis/asciidoctor/asciidoclet/master.svg["Build Status", link="https://travis-ci.org/asciidoctor/asciidoclet"] 34 | image:https://img.shields.io/badge/javadoc.io-{release-version}-blue.svg[Javadoc, link=https://www.javadoc.io/doc/org.asciidoctor/asciidoclet/{release-version}] 35 | endif::[] 36 | 37 | {asciidoclet-src-ref}[Asciidoclet] is a Javadoc Doclet based on Asciidoctor that lets you write Javadoc in the AsciiDoc syntax. 38 | 39 | == Introduction 40 | 41 | Traditionally, Javadocs have mixed minor markup with HTML which, if you're writing for HTML Javadoc output, becomes unreadable and hard to write over time. 42 | This is where lightweight markup languages like {asciidoc-ref}[AsciiDoc] thrive. 43 | AsciiDoc straddles the line between readable markup and beautifully converted content. 44 | 45 | Asciidoclet incorporates an AsciiDoc converter (Asciidoctor via the {asciidoctor-java-ref}[Asciidoctor Java integration] library) into a simple Doclet that enables AsciiDoc formatting within Javadoc comments and tags. 46 | 47 | == Example 48 | 49 | Here's an example of a class with traditional Javadoc. 50 | 51 | [source] 52 | .A Java class with traditional Javadoc 53 | ---- 54 | /** 55 | *

Asciidoclet

56 | * 57 | *

Sample comments that include {@code source code}.

58 | * 59 | *
{@code
 60 |  * public class Asciidoclet extends Doclet {
 61 |  *     private final Asciidoctor asciidoctor = Asciidoctor.Factory.create();
 62 |  *
 63 |  *     {@literal @}SuppressWarnings("UnusedDeclaration")
 64 |  *     public static boolean start(RootDoc rootDoc) {
 65 |  *         new Asciidoclet().render(rootDoc);
 66 |  *         return Standard.start(rootDoc);
 67 |  *     }
 68 |  * }
 69 |  * }
70 | * 71 | * @author John Ericksen 72 | */ 73 | public class Asciidoclet extends Doclet { 74 | } 75 | ---- 76 | 77 | This is the same class with Asciidoclet. 78 | 79 | [source] 80 | .A Java class with Asciidoclet Javadoc 81 | ---- 82 | /** 83 | * = Asciidoclet 84 | * 85 | * Sample comments that include `source code`. 86 | * 87 | * [source,java] 88 | * -- 89 | * public class Asciidoclet extends Doclet { 90 | * private final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); 91 | * 92 | * @SuppressWarnings("UnusedDeclaration") 93 | * public static boolean start(RootDoc rootDoc) { 94 | * new Asciidoclet().render(rootDoc); 95 | * return Standard.start(rootDoc); 96 | * } 97 | * } 98 | * -- 99 | * 100 | * @author https://github.com/johncarl81[John Ericksen] 101 | */ 102 | public class Asciidoclet extends Doclet { 103 | } 104 | ---- 105 | 106 | The result is readable source and beautifully converted Javadocs, the best of both worlds! 107 | 108 | // tag::usage[] 109 | == Usage 110 | 111 | Run Javadoc with the `org.asciidoctor.asciidoctlet.Asciidoclet` doclet class. 112 | Some examples for common build systems are shown below. 113 | See <> for supported options. 114 | 115 | === Maven 116 | 117 | Asciidoclet may be used via a `maven-javadoc-plugin` doclet: 118 | 119 | [source,xml] 120 | ---- 121 | 122 | org.apache.maven.plugins 123 | maven-javadoc-plugin 124 | 3.6.3 125 | 126 | 11 127 | 128 | -J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED 129 | -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED 130 | -J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED 131 | -J--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED 132 | -J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED 133 | -Xdoclint:all,-html,-accessibility 134 | 135 | org.asciidoctor.asciidoclet.Asciidoclet 136 | 137 | org.asciidoctor 138 | asciidoclet 139 | ${asciidoclet.version} 140 | 141 | src/main/java/overview.adoc 142 | 143 | --base-dir ${project.basedir} 144 | --attribute "name=${project.name}" 145 | --attribute "version=${project.version}" 146 | --attribute "title-link=https://example.com[${project.name} ${project.version}]" 147 | 148 | 149 | 150 | ---- 151 | <1> For the asciidoclet to work, it needs access to the internals of the `javadoc` tool. 152 | This incantation makes that access possible on moduler JDKs. 153 | <2> Asciidoctor may generate HTML that produces doclint errors, which can cause the build to fail. 154 | To work around that, we have to disable these doclint categories. 155 | 156 | === Gradle 157 | 158 | Asciidoclet may be used via a doclet in the `Javadoc` task: 159 | 160 | with Kotlin 161 | [source,kotlin] 162 | ---- 163 | val asciiDoclet by configurations.registering 164 | 165 | dependencies { 166 | asciiDoclet("org.asciidoctor:asciidoclet:2.+") 167 | } 168 | 169 | tasks.withType().configureEach { // process *all* javadoc configurations, not just the one for main 170 | options { 171 | doclet("org.asciidoctor.asciidoclet.Asciidoclet") 172 | docletpath(*asciiDoclet.get().files.toTypedArray()) 173 | overview("README.adoc") // you can also point this to the traditional overview like in the groovy example 174 | jFlags( 175 | "--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED", 176 | "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", 177 | "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", 178 | "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", 179 | "--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", 180 | ) 181 | } 182 | (options as StandardJavadocDocletOptions).apply { 183 | addStringOption("-base-dir", project.layout.projectDirectory.asFile.path) // 1 184 | addStringsOption("-attribute", ",").value = listOf("name=${project.name}", "version=${project.version}") // 2 185 | } 186 | } 187 | ---- 188 | 189 | or with groovy, this example only uses main javadoc and will not handle classes generated by source code 190 | [source,groovy] 191 | ---- 192 | configurations { 193 | asciidoclet 194 | } 195 | 196 | dependencies { 197 | asciidoclet 'org.asciidoctor:asciidoclet:2.+' 198 | } 199 | 200 | javadoc { 201 | options.docletpath = configurations.asciidoclet.files.asType(List) 202 | options.doclet = 'org.asciidoctor.asciidoclet.Asciidoclet' 203 | options.overview = "src/main/java/overview.adoc" 204 | options.jFlags = [ 205 | "--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED", 206 | "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", 207 | "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", 208 | "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", 209 | "--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", 210 | ] 211 | options.addStringOption "-base-dir", "${projectDir}" // <1> 212 | options.addStringOption "-attribute", // <2> 213 | "name=${project.name}," + 214 | "version=${project.version}," + 215 | "title-link=https://example.com[${project.name} ${project.version}]") 216 | } 217 | ---- 218 | <1> Option names passed to Gradle's `javadoc` task must omit the leading "-", so here "-base-dir" means "--base-dir". 219 | See <> below. 220 | <2> Gradle's `javadoc` task does not allow multiple occurrences of the same option. 221 | Multiple attributes can be specified in a single string, separated by commas. 222 | 223 | === Ant 224 | // Some of us still use Ant, alright?! 225 | Asciidoclet may be used via a doclet element in Ant's `javadoc` task: 226 | 227 | [source,xml] 228 | ---- 229 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | ---- 240 | 241 | <1> Assumes a path reference has been defined for Asciidoclet and its dependencies, e.g. 242 | using https://ant.apache.org/ivy/[Ivy] or similar. 243 | 244 | === Doclet Options 245 | // tag::doclet-options[] 246 | 247 | --base-dir :: 248 | Sets the base directory that will be used to resolve relative path names in AsciiDoc `include::` directives. 249 | This should be set to the project's root directory. 250 | 251 | -a, --attribute "name[=value], ...":: 252 | Sets https://asciidoctor.org/docs/user-manual/#attributes[document attributes^] that will be expanded in Javadoc comments. 253 | The argument is a string containing a single attribute, or multiple attributes separated by commas. 254 | + 255 | This option may be used more than once, for example: `-a name=foo -a version=1`. 256 | + 257 | Attributes use the same syntax as Asciidoctor command-line attributes: 258 | + 259 | -- 260 | * `name` sets the attribute (with an empty value) 261 | * `name=value` assigns `value` to the attribute. Occurrences of `\{name}` in the Javadoc will be replaced by this value. 262 | * `name=value@` assigns `value` to the attribute, unless the attribute is defined in the attributes file or Javadoc. 263 | * `name!` unsets the attribute. 264 | -- 265 | + 266 | The document attribute `javadoc` is set automatically by the doclet. 267 | This can be used for conditionally selecting content when using the same AsciiDoc file for Javadoc and other documentation. 268 | 269 | --attributes-file :: 270 | Reads https://asciidoctor.org/docs/user-manual/#attributes[document attributes^] from an AsciiDoc file. 271 | The attributes will be expanded in Javadoc comments. 272 | + 273 | If `` is a relative path name, it is assumed to be relative to the `--base-dir` directory. 274 | + 275 | Attributes set by the `-a`/`--attribute` option take precedence over those in the attributes file. 276 | 277 | -r, --require ,...:: 278 | Make the specified RubyGems library available to Asciidoctor's JRuby runtime, for example `-r asciidoctor-diagram`. 279 | + 280 | This option may be specified more than once. 281 | Alternatively multiple library names may be specified in a single argument, separated by commas. 282 | 283 | --gem-path :: 284 | Sets the `GEM_PATH` for Asciidoctor's JRuby runtime. 285 | This option is only needed when using the `--require` option to load additional gems on the `GEM_PATH`. 286 | 287 | -overview :: 288 | Overview documentation can be generated from an AsciiDoc file using the standard `-overview` option. 289 | Files matching [x-]`*.adoc`, [x-]`*.ad`, [x-]`*.asciidoc` or [x-]`*.txt` are processed by Asciidoclet. 290 | Other files are assumed to be HTML and will be processed by the standard doclet. 291 | 292 | --asciidoclet-include :: 293 | --asciidoclet-exclude :: 294 | Explicitly include or exclude classes from being processed as AsciiDoc comments by ant-style path matching (see https://github.com/azagniotov/ant-style-path-matcher[ant-style-path-matcher]). 295 | + 296 | If `--asciidoclet-include` is specified, only classes and packages matching the include filter are processed. 297 | Likewise, if `--include` is unspecified, all classes are processed. 298 | If `--asciidoclet-exclude` is specified, classes matching the filter are not processed. 299 | + 300 | Both `--asciidoclet-include` and `--asciidoclet-exclude` can be mixed. 301 | In addition, classes excluded with `--asciidoclet-exclude` or not matching a specified `--asciidoclet-include` may be included by annotating the class level javadoc with `@asciidoclet`. 302 | Doing so allows writing one class at a time while respecting refactors. 303 | This feature allows the migration of documentation from HTML to AsciiDoc in a piecemeal way. 304 | 305 | // end::doclet-options[] 306 | // end::usage[] 307 | 308 | === Log Warning 309 | 310 | Currently, there is an intermittent benign warning message that is emitted during a run of Asciidoclet stating the following: 311 | 312 | .... 313 | WARN: tilt autoloading 'tilt/haml' in a non thread-safe way; explicit require 'tilt/haml' suggested. 314 | .... 315 | 316 | Unfortunately, until the underlying library removes this warning message, it will be logged during the build. 317 | 318 | == Additional Features 319 | 320 | Make sure to see {asciidoclet-release-ref}[Asciidoclet 1.5.0 Release Notes] for additional features not documented here. 321 | 322 | == Resources and help 323 | 324 | For more information: 325 | 326 | * {asciidoclet-release-ref}[Asciidoclet 1.5.0 Release Notes] 327 | * {asciidoclet-src-ref}[Asciidoclet Source Code] 328 | * {asciidoclet-javadoc-ref}[Asciidoclet JavaDoc] 329 | * {asciidoclet-issues-ref}[Asciidoclet Issue Tracker] 330 | * {asciidoctor-src-ref}[Asciidoctor Source Code] 331 | * {asciidoctor-java-src-ref}[Asciidoctor Java Integration Source Code] 332 | 333 | If you have questions or would like to help develop this project, please join the {discuss-ref}[Asciidoctor Chat]. 334 | 335 | ifndef::env-site[] 336 | == Powered by Asciidoclet 337 | 338 | We have a <> page. 339 | If you have an example of nifty JavaDoc powered by Asciidoclet, please send us a pull request. 340 | endif::[] 341 | 342 | == License 343 | 344 | .... 345 | Copyright (C) 2013-2015 John Ericksen 346 | 347 | Licensed under the Apache License, Version 2.0 (the "License"); 348 | you may not use this file except in compliance with the License. 349 | You may obtain a copy of the License at 350 | 351 | https://www.apache.org/licenses/LICENSE-2.0 352 | 353 | Unless required by applicable law or agreed to in writing, software 354 | distributed under the License is distributed on an "AS IS" BASIS, 355 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 356 | See the License for the specific language governing permissions and 357 | limitations under the License. 358 | .... 359 | -------------------------------------------------------------------------------- /docs/antora.yml: -------------------------------------------------------------------------------- 1 | name: asciidoclet 2 | title: Asciidoclet 3 | version: '2.0' 4 | asciidoc: 5 | attributes: 6 | asciidoclet-version: 2.0.0 7 | asciidoclet-src-ref: https://github.com/asciidoctor/asciidoclet 8 | asciidoclet-javadoc-ref: https://www.javadoc.io/doc/org.asciidoctor/asciidoclet/{asciidoclet-version} 9 | asciidoclet-release-ref: https://asciidoctor.org/news/2014/09/09/asciidoclet-1.5.0-released/ 10 | asciidoc-ref: https://asciidoc.org 11 | asciidoctor-java-ref: https://asciidoctor.org/docs/install-and-use-asciidoctor-java-integration/ 12 | asciidoclet-issues-ref: https://github.com/asciidoctor/asciidoclet/issues 13 | asciidoctor-src-ref: https://github.com/asciidoctor/asciidoctor 14 | asciidoctor-java-src-ref: https://github.com/asciidoctor/asciidoctor-java-integration 15 | discuss-ref: https://discuss.asciidoctor.org/ 16 | 17 | nav: 18 | - modules/ROOT/nav.adoc 19 | - modules/project/nav.adoc 20 | -------------------------------------------------------------------------------- /docs/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | * xref:getting-started.adoc[] 2 | * xref:usage.adoc[] 3 | * xref:options.adoc[] 4 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/additional-features.adoc: -------------------------------------------------------------------------------- 1 | == Additional Features 2 | 3 | Make sure to see {asciidoclet-release-ref}[Asciidoclet 1.5.0 Release Notes] for additional features not documented here. 4 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/getting-started.adoc: -------------------------------------------------------------------------------- 1 | = Getting Started 2 | 3 | Traditionally, Javadocs have mixed minor markup with HTML which, if you're writing for HTML Javadoc output, becomes unreadable and hard to write over time. 4 | This is where lightweight markup languages like {asciidoc-ref}[AsciiDoc] thrive. 5 | AsciiDoc straddles the line between readable markup and beautifully rendered content. 6 | 7 | Asciidoclet incorporates an AsciiDoc converter (Asciidoctor via the {asciidoctor-java-ref}[Asciidoctor Java integration] library) into a simple Doclet that enables AsciiDoc formatting within Javadoc comments and tags. 8 | 9 | == Example 10 | 11 | Here's an example of a class with traditional Javadoc. 12 | 13 | [source,java] 14 | .A Java class with traditional Javadoc 15 | ---- 16 | /** 17 | *

Asciidoclet

18 | * 19 | *

Sample comments that include {@code source code}.

20 | * 21 | *
{@code
22 |  * public class Asciidoclet extends Doclet {
23 |  *     private final Asciidoctor asciidoctor = Asciidoctor.Factory.create();
24 |  *
25 |  *     {@literal @}SuppressWarnings("UnusedDeclaration")
26 |  *     public static boolean start(RootDoc rootDoc) {
27 |  *         new Asciidoclet().render(rootDoc);
28 |  *         return Standard.start(rootDoc);
29 |  *     }
30 |  * }
31 |  * }
32 | * 33 | * @author John Ericksen 34 | */ 35 | public class Asciidoclet extends Doclet { 36 | } 37 | ---- 38 | 39 | This is the same class with Asciidoclet. 40 | 41 | [source,java] 42 | .A Java class with Asciidoclet Javadoc 43 | ---- 44 | /** 45 | * = Asciidoclet 46 | * 47 | * Sample comments that include `source code`. 48 | * 49 | * [source,java] 50 | * -- 51 | * public class Asciidoclet extends Doclet { 52 | * private final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); 53 | * 54 | * @SuppressWarnings("UnusedDeclaration") 55 | * public static boolean start(RootDoc rootDoc) { 56 | * new Asciidoclet().render(rootDoc); 57 | * return Standard.start(rootDoc); 58 | * } 59 | * } 60 | * -- 61 | * 62 | * @author https://github.com/johncarl81[John Ericksen] 63 | */ 64 | public class Asciidoclet extends Doclet { 65 | } 66 | ---- 67 | 68 | The result is readable source and beautifully rendered Javadocs, the best of both worlds! 69 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/index.adoc: -------------------------------------------------------------------------------- 1 | = Asciidoclet 2 | 3 | {asciidoclet-src-ref}[Asciidoclet] is a Javadoc Doclet based on Asciidoctor that lets you write Javadoc in the AsciiDoc syntax. 4 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/options.adoc: -------------------------------------------------------------------------------- 1 | = Doclet Options 2 | :url-asciidoctor-attributes: https://asciidoctor.org/docs/user-manual/#attributes 3 | 4 | --base-dir :: 5 | Sets the base directory that will be used to resolve relative path names in AsciiDoc `include::` directives. 6 | This should be set to the project's root directory. 7 | 8 | -a, --attribute "name[=value], ...":: 9 | Sets {url-asciidoctor-attributes}[document attributes^] that will be expanded in Javadoc comments. 10 | The argument is a string containing a single attribute, or multiple attributes separated by commas. 11 | + 12 | This option may be used more than once, for example: `-a name=foo -a version=1`. 13 | + 14 | Attributes use the same syntax as Asciidoctor command-line attributes: 15 | + 16 | -- 17 | * `name` sets the attribute (with an empty value) 18 | * `name=value` assigns `value` to the attribute. Occurrences of `\{name}` in the Javadoc will be replaced by this value. 19 | * `name=value@` assigns `value` to the attribute, unless the attribute is defined in the attributes file or Javadoc. 20 | * `name!` unsets the attribute. 21 | -- 22 | + 23 | The document attribute `javadoc` is set automatically by the doclet. 24 | This can be used for conditionally selecting content when using the same AsciiDoc file for Javadoc and other documentation. 25 | 26 | --attributes-file :: 27 | Reads {url-asciidoctor-attributes}[document attributes^] from an AsciiDoc file. 28 | The attributes will be expanded in Javadoc comments. 29 | + 30 | If `` is a relative path name, it is assumed to be relative to the `--base-dir` directory. 31 | + 32 | Attributes set by the `-a`/`--attribute` option take precedence over those in the attributes file. 33 | 34 | -r, --require ,...:: 35 | Make the specified RubyGems library available to Asciidoctor's JRuby runtime, for example `-r asciidoctor-diagram`. 36 | + 37 | This option may be specified more than once. 38 | Alternatively multiple library names may be specified in a single argument, separated by commas. 39 | 40 | --gem-path :: 41 | Sets the `GEM_PATH` for Asciidoctor's JRuby runtime. 42 | This option is only needed when using the `--require` option to load additional gems on the `GEM_PATH`. 43 | 44 | -overview :: 45 | Overview documentation can be generated from an AsciiDoc file using the standard `-overview` option. 46 | Files matching [x-]`*.adoc`, [x-]`*.ad`, [x-]`*.asciidoc` or [x-]`*.txt` are processed by Asciidoclet. 47 | Other files are assumed to be HTML and will be processed by the standard doclet. 48 | 49 | --asciidoclet-include :: 50 | --asciidoclet-exclude :: 51 | Explicitly include or exclude classes from being processed as AsciiDoc comments by ant-style path matching (see https://github.com/azagniotov/ant-style-path-matcher[ant-style-path-matcher]). 52 | + 53 | If `--asciidoclet-include` is specified, only classes and packages matching the include filter are processed. 54 | Likewise, if `--include` is unspecified, all classes are processed. 55 | If `--asciidoclet-exclude` is specified, classes matching the filter are not processed. 56 | + 57 | Both `--asciidoclet-include` and `--asciidoclet-exclude` can be mixed. 58 | In addition, classes excluded with `--asciidoclet-exclude` or not matching a specified `--asciidoclet-include` may be included by annotating the class level javadoc with `@asciidoclet`. 59 | Doing so allows writing one class at a time while respecting refactors. 60 | This feature allows the migration of documentation from HTML to AsciiDoc in a piecemeal way. 61 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/usage.adoc: -------------------------------------------------------------------------------- 1 | = Usage 2 | :asciidoclet-class: org.asciidoctor.asciidoclet.Asciidoclet 3 | :maven-javadoc-plugin-version: 3.6.3 4 | 5 | Run Javadoc with the `{asciidoclet-class}` doclet class as shown in the examples below. 6 | See 7 | ifdef::site-gen-antora[xref:options.adoc[]] 8 | ifndef::site-gen-antora[<> below] 9 | for supported options. 10 | 11 | NOTE: Asciidoclet must use some Java runtime internals. 12 | That requires the use of `exports` and `open` configurations depending on the Java version in use. 13 | 14 | == Maven 15 | 16 | Asciidoclet may be used via a `maven-javadoc-plugin` for the supported Java versions. 17 | Pay special attention to `` to configure access to Java internals. 18 | 19 | == Java 11 example 20 | 21 | [source,xml,subs="attributes+"] 22 | ---- 23 | 24 | org.apache.maven.plugins 25 | maven-javadoc-plugin 26 | {maven-javadoc-plugin-version} 27 | 28 | 11 29 | {asciidoclet-class} 30 | 31 | org.asciidoctor 32 | asciidoclet 33 | {asciidoclet-version} 34 | 35 | src/main/java/overview.adoc 36 | 37 | --base-dir ${project.basedir} 38 | --attribute "name=${project.name}" 39 | --attribute "version=${project.version}" 40 | --attribute "title-link=https://example.com[${project.name} ${project.version}]" 41 | 42 | 43 | -J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED 44 | -Xdoclint:all,-html,-accessibility 45 | 46 | 47 | 48 | ---- 49 | 50 | == Java 17+ example 51 | 52 | [source,xml,subs="attributes+"] 53 | ---- 54 | 55 | org.apache.maven.plugins 56 | maven-javadoc-plugin 57 | {maven-javadoc-plugin-version} 58 | 59 | 17 60 | {asciidoclet-class} 61 | 62 | org.asciidoctor 63 | asciidoclet 64 | {asciidoclet-version} 65 | 66 | src/main/java/overview.adoc 67 | 68 | --base-dir ${project.basedir} 69 | --attribute "name=${project.name}" 70 | --attribute "version=${project.version}" 71 | --attribute "title-link=https://example.com[${project.name} ${project.version}]" 72 | 73 | 74 | -J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED 75 | -J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED 76 | -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED 77 | -J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED 78 | -J--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED 79 | -J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED 80 | -Xdoclint:all,-html,-accessibility 81 | 82 | 83 | 84 | ---- 85 | 86 | == Gradle 87 | 88 | Asciidoclet may be used via a doclet in the `Javadoc` task: 89 | Pay special attention to `jFlags` to configure access to Java internals. 90 | 91 | == Java 11 example 92 | 93 | [source,groovy,subs="attributes+"] 94 | ---- 95 | plugins { 96 | id 'java' 97 | } 98 | 99 | configurations { 100 | asciidoclet 101 | } 102 | 103 | dependencies { 104 | asciidoclet 'org.asciidoctor:asciidoclet:{asciidoclet-version}' 105 | } 106 | 107 | javadoc { 108 | options { 109 | docletpath = configurations.asciidoclet.files.asType(List) 110 | doclet = '{asciidoclet-class}' 111 | overview = "src/main/java/overview.adoc" 112 | addStringOption "-base-dir", "$\{projectDir}" // <1> 113 | addStringOption \ 114 | "-attribute", // <2> 115 | "name=${project.name}," + 116 | "version=${project.version}," + 117 | "title-link=https://example.com[${project.name} ${project.version}]" 118 | jFlags \ 119 | "--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED" 120 | } 121 | } 122 | ---- 123 | <1> Option names passed to Gradle's `javadoc` task must omit the leading "-", so here "-base-dir" means "--base-dir". 124 | ifdef::site-gen-antora[See xref:options.adoc[].] 125 | ifndef::site-gen-antora[See <> below.] 126 | <2> Gradle's `javadoc` task does not allow multiple occurrences of the same option. 127 | Multiple attributes can be specified in a single string, separated by commas. 128 | 129 | == Java 17+ example 130 | 131 | [source,groovy,subs="attributes+"] 132 | ---- 133 | plugins { 134 | id 'java' 135 | } 136 | 137 | configurations { 138 | asciidoclet 139 | } 140 | 141 | dependencies { 142 | asciidoclet 'org.asciidoctor:asciidoclet:{asciidoclet-version}' 143 | } 144 | 145 | javadoc { 146 | options { 147 | docletpath = configurations.asciidoclet.files.asType(List) 148 | doclet = '{asciidoclet-class}' 149 | overview = "src/main/java/overview.adoc" 150 | addStringOption "-base-dir", "$\{projectDir}" // <1> 151 | addStringOption \ 152 | "-attribute", // <2> 153 | "name=${project.name}," + 154 | "version=${project.version}," + 155 | "title-link=https://example.com[${project.name} ${project.version}]" 156 | jFlags \ 157 | "--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED", 158 | "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", 159 | "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", 160 | "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", 161 | "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", 162 | "--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED" 163 | } 164 | } 165 | ---- 166 | <1> Option names passed to Gradle's `javadoc` task must omit the leading "-", so here "-base-dir" means "--base-dir". 167 | ifdef::site-gen-antora[See xref:options.adoc[].] 168 | ifndef::site-gen-antora[See <> below.] 169 | <2> Gradle's `javadoc` task does not allow multiple occurrences of the same option. 170 | Multiple attributes can be specified in a single string, separated by commas. 171 | -------------------------------------------------------------------------------- /docs/modules/project/nav.adoc: -------------------------------------------------------------------------------- 1 | * Project Documentation 2 | ** xref:resources.adoc[] 3 | ** xref:powered-by-asciidoclet.adoc[] 4 | ** xref:license.adoc[] 5 | -------------------------------------------------------------------------------- /docs/modules/project/pages/license.adoc: -------------------------------------------------------------------------------- 1 | = License 2 | 3 | .... 4 | Copyright (C) 2013-2015 John Ericksen 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | https://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | .... 18 | -------------------------------------------------------------------------------- /docs/modules/project/pages/powered-by-asciidoclet.adoc: -------------------------------------------------------------------------------- 1 | [#_projects_powered_by_asciidoclet] 2 | = Projects Powered by Asciidoclet 3 | 4 | [cols="2,3,4"] 5 | |=== 6 | |Project |Source |Rendered JavaDoc 7 | 8 | |https://github.com/asciidoctor/asciidoclet[Asciidoclet] 9 | |https://github.com/asciidoctor/asciidoclet[asciidoctor/asciidoclet] 10 | |https://oss.sonatype.org/service/local/repositories/releases/archive/org/asciidoctor/asciidoclet/1.5.4/asciidoclet-1.5.4-javadoc.jar/!/index.html[JavaDoc jar] 11 | 12 | |http://androidtransfuse.org[Transfuse] 13 | |https://github.com/johncarl81/transfuse[johncarl81/transfuse] 14 | |https://oss.sonatype.org/service/local/repositories/releases/archive/org/androidtransfuse/transfuse-api/0.3.0-beta-11/transfuse-api-0.3.0-beta-11-javadoc.jar/!/index.html[JavaDoc jar] 15 | 16 | |http://parceler.org[Parceler] 17 | |https://github.com/johncarl81/parceler[johncarl81/parceler] 18 | |https://oss.sonatype.org/service/local/repositories/releases/archive/org/parceler/parceler-api/1.1.10/parceler-api-1.1.10-javadoc.jar/!/index.html[JavaDoc jar] 19 | 20 | |https://github.com/JGrenier/asciidoclet-sample[asciidoclet-sample] 21 | |https://github.com/JGrenier/asciidoclet-sample[JGrenier/asciidoclet-sample] 22 | |Not available 23 | 24 | |https://consensusj.github.io/consensusj[ConsensusJ] 25 | |https://github.com/ConsensusJ/bitcoinj-addons[ConsensusJ/consensusj] 26 | |https://consensusj.github.io/consensusj/apidoc/index.html[JavaDoc], see http://consensusj.github.io/consensusj/apidoc/com/msgilligan/bitcoinj/rpc/BitcoinClient.html[BitcoinClient] 27 | 28 | |https://chrisvest.github.io/stormpot/[Stormpot] 29 | |https://github.com/chrisvest/stormpot[stormpot] 30 | |http://chrisvest.github.io/stormpot/site/apidocs/stormpot/package-summary.html[JavaDoc] 31 | 32 | |https://valid8j.github.io/valid8j/[Stormpot] 33 | |https://github.com/valid8j/valid8j[valid8j] 34 | |https://valid8j.github.io/valid8j/apidocs/overview-summary.html[JavaDoc] 35 | 36 | |=== 37 | 38 | TIP: Have a cool Asciidoclet-powered project? Edit this file and send us a pull request. 39 | -------------------------------------------------------------------------------- /docs/modules/project/pages/resources.adoc: -------------------------------------------------------------------------------- 1 | = Resources and help 2 | 3 | For more information: 4 | 5 | * {asciidoclet-release-ref}[Asciidoclet 1.5.0 Release Notes] 6 | * {asciidoclet-src-ref}[Asciidoclet Source Code] 7 | * {asciidoclet-javadoc-ref}[Asciidoclet JavaDoc] 8 | * {asciidoclet-issues-ref}[Asciidoclet Issue Tracker] 9 | * {asciidoctor-src-ref}[Asciidoctor Source Code] 10 | * {asciidoctor-java-src-ref}[Asciidoctor Java Integration Source Code] 11 | 12 | If you have questions or would like to help develop this project, please join the {discuss-ref}[Asciidoctor discussion list]. 13 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Apache Maven Wrapper startup batch script, version 3.2.0 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | # e.g. to debug Maven itself, use 32 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | # ---------------------------------------------------------------------------- 35 | 36 | if [ -z "$MAVEN_SKIP_RC" ] ; then 37 | 38 | if [ -f /usr/local/etc/mavenrc ] ; then 39 | . /usr/local/etc/mavenrc 40 | fi 41 | 42 | if [ -f /etc/mavenrc ] ; then 43 | . /etc/mavenrc 44 | fi 45 | 46 | if [ -f "$HOME/.mavenrc" ] ; then 47 | . "$HOME/.mavenrc" 48 | fi 49 | 50 | fi 51 | 52 | # OS specific support. $var _must_ be set to either true or false. 53 | cygwin=false; 54 | darwin=false; 55 | mingw=false 56 | case "$(uname)" in 57 | CYGWIN*) cygwin=true ;; 58 | MINGW*) mingw=true;; 59 | Darwin*) darwin=true 60 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 61 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 62 | if [ -z "$JAVA_HOME" ]; then 63 | if [ -x "/usr/libexec/java_home" ]; then 64 | JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME 65 | else 66 | JAVA_HOME="/Library/Java/Home"; export JAVA_HOME 67 | fi 68 | fi 69 | ;; 70 | esac 71 | 72 | if [ -z "$JAVA_HOME" ] ; then 73 | if [ -r /etc/gentoo-release ] ; then 74 | JAVA_HOME=$(java-config --jre-home) 75 | fi 76 | fi 77 | 78 | # For Cygwin, ensure paths are in UNIX format before anything is touched 79 | if $cygwin ; then 80 | [ -n "$JAVA_HOME" ] && 81 | JAVA_HOME=$(cygpath --unix "$JAVA_HOME") 82 | [ -n "$CLASSPATH" ] && 83 | CLASSPATH=$(cygpath --path --unix "$CLASSPATH") 84 | fi 85 | 86 | # For Mingw, ensure paths are in UNIX format before anything is touched 87 | if $mingw ; then 88 | [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && 89 | JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" 90 | fi 91 | 92 | if [ -z "$JAVA_HOME" ]; then 93 | javaExecutable="$(which javac)" 94 | if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then 95 | # readlink(1) is not available as standard on Solaris 10. 96 | readLink=$(which readlink) 97 | if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then 98 | if $darwin ; then 99 | javaHome="$(dirname "\"$javaExecutable\"")" 100 | javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" 101 | else 102 | javaExecutable="$(readlink -f "\"$javaExecutable\"")" 103 | fi 104 | javaHome="$(dirname "\"$javaExecutable\"")" 105 | javaHome=$(expr "$javaHome" : '\(.*\)/bin') 106 | JAVA_HOME="$javaHome" 107 | export JAVA_HOME 108 | fi 109 | fi 110 | fi 111 | 112 | if [ -z "$JAVACMD" ] ; then 113 | if [ -n "$JAVA_HOME" ] ; then 114 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 115 | # IBM's JDK on AIX uses strange locations for the executables 116 | JAVACMD="$JAVA_HOME/jre/sh/java" 117 | else 118 | JAVACMD="$JAVA_HOME/bin/java" 119 | fi 120 | else 121 | JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" 122 | fi 123 | fi 124 | 125 | if [ ! -x "$JAVACMD" ] ; then 126 | echo "Error: JAVA_HOME is not defined correctly." >&2 127 | echo " We cannot execute $JAVACMD" >&2 128 | exit 1 129 | fi 130 | 131 | if [ -z "$JAVA_HOME" ] ; then 132 | echo "Warning: JAVA_HOME environment variable is not set." 133 | fi 134 | 135 | # traverses directory structure from process work directory to filesystem root 136 | # first directory with .mvn subdirectory is considered project base directory 137 | find_maven_basedir() { 138 | if [ -z "$1" ] 139 | then 140 | echo "Path not specified to find_maven_basedir" 141 | return 1 142 | fi 143 | 144 | basedir="$1" 145 | wdir="$1" 146 | while [ "$wdir" != '/' ] ; do 147 | if [ -d "$wdir"/.mvn ] ; then 148 | basedir=$wdir 149 | break 150 | fi 151 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 152 | if [ -d "${wdir}" ]; then 153 | wdir=$(cd "$wdir/.." || exit 1; pwd) 154 | fi 155 | # end of workaround 156 | done 157 | printf '%s' "$(cd "$basedir" || exit 1; pwd)" 158 | } 159 | 160 | # concatenates all lines of a file 161 | concat_lines() { 162 | if [ -f "$1" ]; then 163 | # Remove \r in case we run on Windows within Git Bash 164 | # and check out the repository with auto CRLF management 165 | # enabled. Otherwise, we may read lines that are delimited with 166 | # \r\n and produce $'-Xarg\r' rather than -Xarg due to word 167 | # splitting rules. 168 | tr -s '\r\n' ' ' < "$1" 169 | fi 170 | } 171 | 172 | log() { 173 | if [ "$MVNW_VERBOSE" = true ]; then 174 | printf '%s\n' "$1" 175 | fi 176 | } 177 | 178 | BASE_DIR=$(find_maven_basedir "$(dirname "$0")") 179 | if [ -z "$BASE_DIR" ]; then 180 | exit 1; 181 | fi 182 | 183 | MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR 184 | log "$MAVEN_PROJECTBASEDIR" 185 | 186 | ########################################################################################## 187 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 188 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 189 | ########################################################################################## 190 | wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" 191 | if [ -r "$wrapperJarPath" ]; then 192 | log "Found $wrapperJarPath" 193 | else 194 | log "Couldn't find $wrapperJarPath, downloading it ..." 195 | 196 | if [ -n "$MVNW_REPOURL" ]; then 197 | wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" 198 | else 199 | wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" 200 | fi 201 | while IFS="=" read -r key value; do 202 | # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) 203 | safeValue=$(echo "$value" | tr -d '\r') 204 | case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; 205 | esac 206 | done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" 207 | log "Downloading from: $wrapperUrl" 208 | 209 | if $cygwin; then 210 | wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") 211 | fi 212 | 213 | if command -v wget > /dev/null; then 214 | log "Found wget ... using wget" 215 | [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" 216 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 217 | wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 218 | else 219 | wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 220 | fi 221 | elif command -v curl > /dev/null; then 222 | log "Found curl ... using curl" 223 | [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" 224 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 225 | curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" 226 | else 227 | curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" 228 | fi 229 | else 230 | log "Falling back to using Java to download" 231 | javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" 232 | javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" 233 | # For Cygwin, switch paths to Windows format before running javac 234 | if $cygwin; then 235 | javaSource=$(cygpath --path --windows "$javaSource") 236 | javaClass=$(cygpath --path --windows "$javaClass") 237 | fi 238 | if [ -e "$javaSource" ]; then 239 | if [ ! -e "$javaClass" ]; then 240 | log " - Compiling MavenWrapperDownloader.java ..." 241 | ("$JAVA_HOME/bin/javac" "$javaSource") 242 | fi 243 | if [ -e "$javaClass" ]; then 244 | log " - Running MavenWrapperDownloader.java ..." 245 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" 246 | fi 247 | fi 248 | fi 249 | fi 250 | ########################################################################################## 251 | # End of extension 252 | ########################################################################################## 253 | 254 | # If specified, validate the SHA-256 sum of the Maven wrapper jar file 255 | wrapperSha256Sum="" 256 | while IFS="=" read -r key value; do 257 | case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; 258 | esac 259 | done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" 260 | if [ -n "$wrapperSha256Sum" ]; then 261 | wrapperSha256Result=false 262 | if command -v sha256sum > /dev/null; then 263 | if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then 264 | wrapperSha256Result=true 265 | fi 266 | elif command -v shasum > /dev/null; then 267 | if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then 268 | wrapperSha256Result=true 269 | fi 270 | else 271 | echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." 272 | echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." 273 | exit 1 274 | fi 275 | if [ $wrapperSha256Result = false ]; then 276 | echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 277 | echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 278 | echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 279 | exit 1 280 | fi 281 | fi 282 | 283 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 284 | 285 | # For Cygwin, switch paths to Windows format before running java 286 | if $cygwin; then 287 | [ -n "$JAVA_HOME" ] && 288 | JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") 289 | [ -n "$CLASSPATH" ] && 290 | CLASSPATH=$(cygpath --path --windows "$CLASSPATH") 291 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 292 | MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") 293 | fi 294 | 295 | # Provide a "standardized" way to retrieve the CLI args that will 296 | # work with both Windows and non-Windows executions. 297 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" 298 | export MAVEN_CMD_LINE_ARGS 299 | 300 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 301 | 302 | # shellcheck disable=SC2086 # safe args 303 | exec "$JAVACMD" \ 304 | $MAVEN_OPTS \ 305 | $MAVEN_DEBUG_OPTS \ 306 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 307 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 308 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 309 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Apache Maven Wrapper startup batch script, version 3.2.0 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 28 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 29 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 30 | @REM e.g. to debug Maven itself, use 31 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 32 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 33 | @REM ---------------------------------------------------------------------------- 34 | 35 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 36 | @echo off 37 | @REM set title of command window 38 | title %0 39 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 40 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 41 | 42 | @REM set %HOME% to equivalent of $HOME 43 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 44 | 45 | @REM Execute a user defined script before this one 46 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 47 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 48 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 49 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 50 | :skipRcPre 51 | 52 | @setlocal 53 | 54 | set ERROR_CODE=0 55 | 56 | @REM To isolate internal variables from possible post scripts, we use another setlocal 57 | @setlocal 58 | 59 | @REM ==== START VALIDATION ==== 60 | if not "%JAVA_HOME%" == "" goto OkJHome 61 | 62 | echo. 63 | echo Error: JAVA_HOME not found in your environment. >&2 64 | echo Please set the JAVA_HOME variable in your environment to match the >&2 65 | echo location of your Java installation. >&2 66 | echo. 67 | goto error 68 | 69 | :OkJHome 70 | if exist "%JAVA_HOME%\bin\java.exe" goto init 71 | 72 | echo. 73 | echo Error: JAVA_HOME is set to an invalid directory. >&2 74 | echo JAVA_HOME = "%JAVA_HOME%" >&2 75 | echo Please set the JAVA_HOME variable in your environment to match the >&2 76 | echo location of your Java installation. >&2 77 | echo. 78 | goto error 79 | 80 | @REM ==== END VALIDATION ==== 81 | 82 | :init 83 | 84 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 85 | @REM Fallback to current working directory if not found. 86 | 87 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 88 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 89 | 90 | set EXEC_DIR=%CD% 91 | set WDIR=%EXEC_DIR% 92 | :findBaseDir 93 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 94 | cd .. 95 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 96 | set WDIR=%CD% 97 | goto findBaseDir 98 | 99 | :baseDirFound 100 | set MAVEN_PROJECTBASEDIR=%WDIR% 101 | cd "%EXEC_DIR%" 102 | goto endDetectBaseDir 103 | 104 | :baseDirNotFound 105 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 106 | cd "%EXEC_DIR%" 107 | 108 | :endDetectBaseDir 109 | 110 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 111 | 112 | @setlocal EnableExtensions EnableDelayedExpansion 113 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 114 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 115 | 116 | :endReadAdditionalConfig 117 | 118 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" 123 | 124 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 125 | IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | if "%MVNW_VERBOSE%" == "true" ( 132 | echo Found %WRAPPER_JAR% 133 | ) 134 | ) else ( 135 | if not "%MVNW_REPOURL%" == "" ( 136 | SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" 137 | ) 138 | if "%MVNW_VERBOSE%" == "true" ( 139 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 140 | echo Downloading from: %WRAPPER_URL% 141 | ) 142 | 143 | powershell -Command "&{"^ 144 | "$webclient = new-object System.Net.WebClient;"^ 145 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 146 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 147 | "}"^ 148 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ 149 | "}" 150 | if "%MVNW_VERBOSE%" == "true" ( 151 | echo Finished downloading %WRAPPER_JAR% 152 | ) 153 | ) 154 | @REM End of extension 155 | 156 | @REM If specified, validate the SHA-256 sum of the Maven wrapper jar file 157 | SET WRAPPER_SHA_256_SUM="" 158 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 159 | IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B 160 | ) 161 | IF NOT %WRAPPER_SHA_256_SUM%=="" ( 162 | powershell -Command "&{"^ 163 | "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ 164 | "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ 165 | " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ 166 | " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ 167 | " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ 168 | " exit 1;"^ 169 | "}"^ 170 | "}" 171 | if ERRORLEVEL 1 goto error 172 | ) 173 | 174 | @REM Provide a "standardized" way to retrieve the CLI args that will 175 | @REM work with both Windows and non-Windows executions. 176 | set MAVEN_CMD_LINE_ARGS=%* 177 | 178 | %MAVEN_JAVA_EXE% ^ 179 | %JVM_CONFIG_MAVEN_PROPS% ^ 180 | %MAVEN_OPTS% ^ 181 | %MAVEN_DEBUG_OPTS% ^ 182 | -classpath %WRAPPER_JAR% ^ 183 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 184 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 185 | if ERRORLEVEL 1 goto error 186 | goto end 187 | 188 | :error 189 | set ERROR_CODE=1 190 | 191 | :end 192 | @endlocal & set ERROR_CODE=%ERROR_CODE% 193 | 194 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 195 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 196 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 197 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 198 | :skipRcPost 199 | 200 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 201 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 202 | 203 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 204 | 205 | cmd /C exit /B %ERROR_CODE% 206 | -------------------------------------------------------------------------------- /src/docs/asciidoc/release-process.adoc: -------------------------------------------------------------------------------- 1 | = Asciidoclet Release Process 2 | 3 | == Introduction 4 | 5 | This document describes the release procedures used for releasing Asciidoclet. Currently releases are made by https://github.com/johncarl81[@johncarl81] who has all the necessary access credentials. 6 | 7 | == Snapshot releases 8 | 9 | Snapshot releases are published to the Sonatype snapshot repository, which would be configured for read access in Gradle as follows: 10 | 11 | 12 | repositories { 13 | maven { 14 | url 'https://oss.sonatype.org/content/repositories/snapshots/' 15 | } 16 | } 17 | 18 | Deployment is done via the Maven command line with the following command: 19 | 20 | mvn clean deploy 21 | 22 | TBD: Document how to set up credentials for publishing. 23 | 24 | == Official releases 25 | 26 | TBD. 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/it/java-11/class-comments/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals=clean javadoc:javadoc 2 | -------------------------------------------------------------------------------- /src/it/java-11/class-comments/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.asciidoctor 6 | test 7 | 1.0.0-SNAPSHOT 8 | Integration Test: generate Javadoc for class and method 9 | 10 | 11 | UTF-8 12 | 13 | 14 | 15 | 16 | 17 | org.apache.maven.plugins 18 | maven-javadoc-plugin 19 | 3.6.3 20 | 21 | 11 22 | 23 | -J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED 24 | -Xdoclint:all,-html,-accessibility 25 | 26 | org.asciidoctor.asciidoclet.Asciidoclet 27 | 28 | 29 | org.asciidoctor 30 | asciidoclet 31 | @project.version@ 32 | 33 | 34 | src/main/java/overview.adoc 35 | 36 | --base-dir ${project.basedir} 37 | --attribute "project_name=${project.name}" 38 | --attribute "project_description=${project.description}" 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/it/java-11/class-comments/src/main/java/example/StringUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example; 17 | 18 | /** 19 | * Class comment for "{project_description}". 20 | */ 21 | public class StringUtils { 22 | 23 | /** 24 | * This is a method comment. 25 | * 26 | * @param haystack the haystack 27 | * @param needle it stings 28 | * @return true if lucky 29 | */ 30 | public boolean contains(String haystack, String needle) { 31 | return haystack.contains(needle); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/it/java-11/class-comments/validate.groovy: -------------------------------------------------------------------------------- 1 | import java.nio.file.Files 2 | import java.nio.file.Path 3 | 4 | String javaVersion = System.getProperty('java.version').split("\\.")[0] 5 | if (javaVersion != expected_java) { 6 | throw new Exception("Invalid Java version. Expected ${expected_java}, found $javaVersion") 7 | } 8 | 9 | def javadocExpectedPath = Path.of((String) basedir).resolve('target/site/apidocs') 10 | def expectedJavadoc = javadocExpectedPath.resolve('example/StringUtils.html') 11 | 12 | if (Files.list(javadocExpectedPath).count() == 0) { 13 | throw new Exception("${javadocExpectedPath.toFile().getAbsolutePath()} path cannot me empty") 14 | } 15 | 16 | def javadocContent = Files.readString(expectedJavadoc) 17 | 18 | def expectClassDescription = Html.div(Html.p('Class comment for "Integration Test: generate Javadoc for class and method".'), 'block') 19 | def expectMethodDescription = Html.div(Html.p('This is a method comment.'), 'block') 20 | 21 | assertStringContains(javadocContent, expectClassDescription) 22 | assertStringContains(javadocContent, expectMethodDescription) 23 | 24 | def expectMethodArgument1 = Html.dd(Html.code('haystack') + " - the haystack") 25 | def expectMethodArgument2 = Html.dd(Html.code('needle') + " - it stings") 26 | 27 | assertStringContains(javadocContent, expectMethodArgument1) 28 | assertStringContains(javadocContent, expectMethodArgument2) 29 | 30 | def expectMethodReturn = Html.dt(Html.span("Returns:", "returnLabel")) + System.lineSeparator() + Html.dd('true if lucky') 31 | 32 | assertStringContains(javadocContent, expectMethodReturn) 33 | 34 | 35 | void assertStringContains(String value, String expected) { 36 | if (!value.contains(expected)) { 37 | throw new Exception("'$expected' expected to be present") 38 | } 39 | } 40 | 41 | class Html { 42 | 43 | static String div(String text, String classname) { 44 | return "
${text}
" 45 | } 46 | 47 | static String span(String text, String classname) { 48 | return "${text}" 49 | } 50 | 51 | static String p(String text) { 52 | return "

${text}

" 53 | } 54 | 55 | static String code(String text) { 56 | return "${text}" 57 | } 58 | 59 | static String dd(String text) { 60 | return "
${text}
" 61 | } 62 | 63 | static String dt(String text) { 64 | return "
${text}
" 65 | } 66 | } 67 | 68 | return true 69 | -------------------------------------------------------------------------------- /src/it/java-17/class-comments/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals=clean javadoc:javadoc 2 | -------------------------------------------------------------------------------- /src/it/java-17/class-comments/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.asciidoctor 6 | test 7 | 1.0.0-SNAPSHOT 8 | Integration Test: generate Javadoc for class and method 9 | 10 | 11 | UTF-8 12 | 13 | 14 | 15 | 16 | 17 | org.apache.maven.plugins 18 | maven-javadoc-plugin 19 | 3.6.3 20 | 21 | 17 22 | 23 | -J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED 24 | -J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED 25 | -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED 26 | -J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED 27 | -J--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED 28 | -J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED 29 | -Xdoclint:all,-html,-accessibility 30 | 31 | org.asciidoctor.asciidoclet.Asciidoclet 32 | 33 | 34 | org.asciidoctor 35 | asciidoclet 36 | @project.version@ 37 | 38 | 39 | src/main/java/overview.adoc 40 | 41 | --base-dir ${project.basedir} 42 | --attribute "project_name=${project.name}" 43 | --attribute "project_description=${project.description}" 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/it/java-17/class-comments/src/main/java/example/StringUtils.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | /** 4 | * Class comment for "{project_description}". 5 | */ 6 | public class StringUtils { 7 | 8 | /** 9 | * This is a method comment. 10 | * 11 | * @param haystack the haystack 12 | * @param needle it stings 13 | * @return true if lucky 14 | */ 15 | public boolean contains(String haystack, String needle) { 16 | return haystack.contains(needle); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/it/java-17/class-comments/validate.groovy: -------------------------------------------------------------------------------- 1 | import java.nio.file.Files 2 | import java.nio.file.Path 3 | 4 | String javaVersion = System.getProperty('java.version').split("\\.")[0] 5 | if (javaVersion != expected_java) { 6 | throw new Exception("Invalid Java version. Expected ${expected_java}, found $javaVersion") 7 | } 8 | 9 | def javadocExpectedPath = Path.of((String) basedir).resolve('target/site/apidocs') 10 | def expectedJavadoc = javadocExpectedPath.resolve('example/StringUtils.html') 11 | 12 | if (Files.list(javadocExpectedPath).count() == 0) { 13 | throw new Exception("${javadocExpectedPath.toFile().getAbsolutePath()} path cannot me empty") 14 | } 15 | 16 | def javadocContent = Files.readString(expectedJavadoc) 17 | 18 | def expectClassDescription = Html.div(Html.p('Class comment for "Integration Test: generate Javadoc for class and method".'), 'block') 19 | def expectMethodDescription = Html.div(Html.p('This is a method comment.'), 'block') 20 | 21 | assertStringContains(javadocContent, expectClassDescription) 22 | assertStringContains(javadocContent, expectMethodDescription) 23 | 24 | def expectMethodArgument1 = Html.dd(Html.code('haystack') + " - the haystack") 25 | def expectMethodArgument2 = Html.dd(Html.code('needle') + " - it stings") 26 | 27 | assertStringContains(javadocContent, expectMethodArgument1) 28 | assertStringContains(javadocContent, expectMethodArgument2) 29 | 30 | def expectMethodReturn = Html.dt("Returns:") + System.lineSeparator() + Html.dd('true if lucky') 31 | 32 | assertStringContains(javadocContent, expectMethodReturn) 33 | 34 | 35 | void assertStringContains(String value, String expected) { 36 | if (!value.contains(expected)) { 37 | throw new Exception("'$expected' expected to be present") 38 | } 39 | } 40 | 41 | class Html { 42 | 43 | static String div(String text, String classname) { 44 | return "
${text}
" 45 | } 46 | 47 | static String p(String text) { 48 | return "

${text}

" 49 | } 50 | 51 | static String code(String text) { 52 | return "${text}" 53 | } 54 | 55 | static String dd(String text) { 56 | return "
${text}
" 57 | } 58 | 59 | static String dt(String text) { 60 | return "
${text}
" 61 | } 62 | } 63 | 64 | return true 65 | -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * A module-info for `asciidoclet`. 18 | */ 19 | module asciidoclet { 20 | requires java.base; 21 | requires jdk.compiler; 22 | requires jdk.javadoc; 23 | requires asciidoctorj; 24 | requires asciidoctorj.api; 25 | exports org.asciidoctor.asciidoclet; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/AntPathMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | /** 19 | * Path matcher implementation for Ant-style path patterns. This implementation matches URLs using the following rules: 20 | * 21 | * * `?` matches one character 22 | * * `*` matches zero or more characters 23 | * * `**` matches zero or more directories in a path 24 | * 25 | * The instances of this class can be configured via its {@link Builder} to: 26 | * 27 | * 1. Use a custom path separator. The default is `/` character 28 | * 2. Ignore character case during comparison. The default is `false` 29 | * 3. Match start. Determines whether the pattern at least matches as far as the given base path goes, 30 | * assuming that a full path may then match as well. The default is `false`. 31 | * 4. Specify whether to trim tokenized paths. The default is `false` 32 | * 33 | * The custom path separator & ignoring character case options were inspired by Spring's `AntPathMatcher` 34 | * 35 | * Class copied from https://github.com/azagniotov/ant-style-path-matcher 36 | */ 37 | @SuppressWarnings("WeakerAccess") 38 | public class AntPathMatcher { 39 | 40 | private static final char ASTERISK = '*'; 41 | private static final char QUESTION = '?'; 42 | private static final char BLANK = ' '; 43 | private static final int ASCII_CASE_DIFFERENCE_VALUE = 32; 44 | 45 | private final char pathSeparator; 46 | private final boolean ignoreCase; 47 | private final boolean matchStart; 48 | private final boolean trimTokens; 49 | 50 | private AntPathMatcher(final char pathSeparator, boolean ignoreCase, boolean matchStart, boolean trimTokens) { 51 | this.pathSeparator = pathSeparator; 52 | this.ignoreCase = ignoreCase; 53 | this.matchStart = matchStart; 54 | this.trimTokens = trimTokens; 55 | } 56 | 57 | /** 58 | * Checks if a `path` matches with a given `pattern`. 59 | * Is this method really necessary? 60 | * 61 | * @param pattern A pattern to be checked with a `path`. 62 | * @param path A path to be checked 63 | * @return `true` if `path` matches `pattern`. `false`, otherwise. 64 | */ 65 | 66 | public boolean isMatch(final String pattern, final String path) { 67 | if (pattern.isEmpty()) { 68 | return path.isEmpty(); 69 | } else if (path.isEmpty() && pattern.charAt(0) == pathSeparator) { 70 | if (matchStart) { 71 | return true; 72 | } else if (pattern.length() == 2 && pattern.charAt(1) == ASTERISK) { 73 | return false; 74 | } 75 | return isMatch(pattern.substring(1), path); 76 | } 77 | 78 | final char patternStart = pattern.charAt(0); 79 | if (patternStart == ASTERISK) { 80 | 81 | if (pattern.length() == 1) { 82 | return path.isEmpty() || path.charAt(0) != pathSeparator && isMatch(pattern, path.substring(1)); 83 | } else if (doubleAsteriskMatch(pattern, path)) { 84 | return true; 85 | } 86 | 87 | int start = 0; 88 | while (start < path.length()) { 89 | if (isMatch(pattern.substring(1), path.substring(start))) { 90 | return true; 91 | } 92 | start++; 93 | } 94 | return isMatch(pattern.substring(1), path.substring(start)); 95 | } 96 | 97 | int pointer = skipBlanks(path); 98 | 99 | return !path.isEmpty() && (equal(path.charAt(pointer), patternStart) || patternStart == QUESTION) 100 | && isMatch(pattern.substring(1), path.substring(pointer + 1)); 101 | } 102 | 103 | private boolean doubleAsteriskMatch(final String pattern, final String path) { 104 | if (pattern.charAt(1) != ASTERISK) { 105 | return false; 106 | } else if (pattern.length() > 2) { 107 | return isMatch(pattern.substring(3), path); 108 | } 109 | 110 | return false; 111 | } 112 | 113 | private int skipBlanks(final String path) { 114 | int pointer = 0; 115 | if (trimTokens) { 116 | while (!path.isEmpty() && pointer < path.length() && path.charAt(pointer) == BLANK) { 117 | pointer++; 118 | } 119 | } 120 | return pointer; 121 | } 122 | 123 | private boolean equal(final char pathChar, final char patternChar) { 124 | if (ignoreCase) { 125 | return pathChar == patternChar || 126 | ((pathChar > patternChar) ? 127 | pathChar == patternChar + ASCII_CASE_DIFFERENCE_VALUE : 128 | pathChar == patternChar - ASCII_CASE_DIFFERENCE_VALUE); 129 | } 130 | return pathChar == patternChar; 131 | } 132 | 133 | /** 134 | * A builder class for `AndPathMatcher`. 135 | * Is this class really necessary? 136 | * // A comment to suppress warnings during JavaDoc generation by AsciiDoclet. 137 | */ 138 | public static final class Builder { 139 | 140 | private char pathSeparator = '/'; 141 | private boolean ignoreCase = false; 142 | private boolean matchStart = false; 143 | private boolean trimTokens = false; 144 | 145 | /** 146 | * Creates {@link Builder} object. 147 | */ 148 | public Builder() { 149 | 150 | } 151 | 152 | /** 153 | * Sets `pathSeparator` to this object. 154 | * 155 | * @param pathSeparator `pathSeparator` to be set. 156 | * @return returns this object. 157 | */ 158 | public Builder withPathSeparator(final char pathSeparator) { 159 | this.pathSeparator = pathSeparator; 160 | return this; 161 | } 162 | 163 | /** 164 | * Sets `ignoreCase` to this object to `true`. 165 | * @return returns this object. 166 | */ 167 | public Builder withIgnoreCase() { 168 | this.ignoreCase = true; 169 | return this; 170 | } 171 | 172 | /** 173 | * Sets `matchStart` to this object to `true`. 174 | * @return returns this object. 175 | */ 176 | public Builder withMatchStart() { 177 | this.matchStart = true; 178 | return this; 179 | } 180 | 181 | /** 182 | * Sets `trimTokens` to this object to `true`. 183 | * @return returns this object. 184 | */ 185 | public Builder withTrimTokens() { 186 | this.trimTokens = true; 187 | return this; 188 | } 189 | 190 | /** 191 | * Creates and returns {@link AntPathMatcher} object. 192 | * @return A built {@link AntPathMatcher} object. 193 | */ 194 | public AntPathMatcher build() { 195 | return new AntPathMatcher(pathSeparator, ignoreCase, matchStart, trimTokens); 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/AsciiDocTrees.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import com.sun.source.doctree.DocCommentTree; 19 | import com.sun.source.doctree.DocTree; 20 | import com.sun.source.doctree.EntityTree; 21 | import com.sun.source.tree.CatchTree; 22 | import com.sun.source.tree.ClassTree; 23 | import com.sun.source.tree.CompilationUnitTree; 24 | import com.sun.source.tree.MethodTree; 25 | import com.sun.source.tree.Scope; 26 | import com.sun.source.tree.Tree; 27 | import com.sun.source.util.DocSourcePositions; 28 | import com.sun.source.util.DocTreeFactory; 29 | import com.sun.source.util.DocTreePath; 30 | import com.sun.source.util.DocTrees; 31 | import com.sun.source.util.TreePath; 32 | import com.sun.tools.javac.model.JavacElements; 33 | import com.sun.tools.javac.parser.Tokens; 34 | import com.sun.tools.javac.tree.JCTree; 35 | 36 | import javax.lang.model.element.AnnotationMirror; 37 | import javax.lang.model.element.AnnotationValue; 38 | import javax.lang.model.element.Element; 39 | import javax.lang.model.element.ExecutableElement; 40 | import javax.lang.model.element.PackageElement; 41 | import javax.lang.model.element.TypeElement; 42 | import javax.lang.model.type.DeclaredType; 43 | import javax.lang.model.type.ErrorType; 44 | import javax.lang.model.type.TypeMirror; 45 | import javax.tools.Diagnostic; 46 | import javax.tools.FileObject; 47 | import javax.tools.JavaFileManager; 48 | import javax.tools.StandardJavaFileManager; 49 | import java.io.FileNotFoundException; 50 | import java.io.IOException; 51 | import java.lang.reflect.Field; 52 | import java.lang.reflect.InvocationTargetException; 53 | import java.text.BreakIterator; 54 | import java.util.List; 55 | 56 | import static javax.tools.StandardLocation.SOURCE_PATH; 57 | 58 | class AsciiDocTrees extends DocTrees { 59 | 60 | private final AsciidoctorConverter converter; 61 | private final StandardJavaFileManager fileManager; 62 | private final DocTrees docTrees; 63 | private final Field elementsField; 64 | 65 | AsciiDocTrees(AsciidoctorConverter converter, StandardJavaFileManager fileManager, DocTrees docTrees) { 66 | this.converter = converter; 67 | this.fileManager = fileManager; 68 | this.docTrees = docTrees; 69 | try { 70 | this.elementsField = docTrees.getClass().getDeclaredField("elements"); 71 | this.elementsField.setAccessible(true); 72 | } catch (Exception e) { 73 | throw new RuntimeException(e); 74 | } 75 | } 76 | 77 | @Override 78 | public BreakIterator getBreakIterator() { 79 | return docTrees.getBreakIterator(); 80 | } 81 | 82 | @Override 83 | public String getDocComment(TreePath path) { 84 | return converter.convert(docTrees.getDocComment(path)); 85 | } 86 | 87 | @Override 88 | public DocCommentTree getDocCommentTree(TreePath path) { 89 | // First we convert the asciidoctor to HTML inside the AST. 90 | JCTree.JCCompilationUnit cu = (JCTree.JCCompilationUnit) path.getCompilationUnit(); 91 | LazyDocCommentTableProcessor.processComments(cu.docComments, this::convertToAsciidoctor); 92 | // Then we allow the normal javadoc parsing to continue on the asciidoctor result. 93 | return docTrees.getDocCommentTree(path); 94 | } 95 | 96 | private Tokens.Comment convertToAsciidoctor(Tokens.Comment comment) { 97 | String asciidoc = convertJavadocStringToAsciidoctorString(comment.getText()); 98 | AsciidocComment result = new AsciidocComment(asciidoc, comment); 99 | return result; 100 | } 101 | 102 | private String convertJavadocStringToAsciidoctorString(String javadocString) { 103 | return converter.convert(javadocString); 104 | } 105 | 106 | @Override 107 | public DocCommentTree getDocCommentTree(Element e) { 108 | TreePath path = getPath(e); 109 | if (path == null) { 110 | return null; 111 | } 112 | return getDocCommentTree(path); 113 | } 114 | 115 | @Override 116 | public DocCommentTree getDocCommentTree(FileObject fileObject) { 117 | // Empty names are used for built-in headers and footers, which need no asciidoctor processing anyway. 118 | if (!fileObject.getName().isEmpty() && !(fileObject instanceof AsciidocFileView)) { 119 | return docTrees.getDocCommentTree(new AsciidocFileView(converter, fileObject)); 120 | } 121 | return docTrees.getDocCommentTree(fileObject); 122 | } 123 | 124 | @Override 125 | public DocCommentTree getDocCommentTree(Element e, String relativePath) throws IOException { 126 | PackageElement pkg = getElements().getPackageOf(e); 127 | JavaFileManager fileManager = getFileManager(); 128 | FileObject input = fileManager.getFileForInput(SOURCE_PATH, pkg.getQualifiedName().toString(), relativePath); 129 | if (input == null) { 130 | throw new FileNotFoundException(relativePath); 131 | } 132 | return getDocCommentTree(input); 133 | } 134 | 135 | private JavacElements getElements() { 136 | try { 137 | return (JavacElements) elementsField.get(docTrees); 138 | } catch (Exception e) { 139 | throw new RuntimeException(e); 140 | } 141 | } 142 | 143 | private JavaFileManager getFileManager() { 144 | return fileManager; 145 | } 146 | 147 | @Override 148 | public DocTreePath getDocTreePath(FileObject fileObject, PackageElement packageElement) { 149 | return docTrees.getDocTreePath(fileObject, packageElement); 150 | } 151 | 152 | @Override 153 | public Element getElement(DocTreePath path) { 154 | return docTrees.getElement(path); 155 | } 156 | 157 | // Not giving @Override in order to make this class compilable under all of JDK 11, 17, 21. 158 | public TypeMirror getType(DocTreePath path) { 159 | // In order to make this method compilable with JDK11, which doesn't define DocTrees#getType method, 160 | // and make this method work with JDK 17 and later, invoke the DocTrees#getType(DocTreePath) method reflectively. 161 | // Once we decide to stop supporting JDK 11, just call getType directly. 162 | try { 163 | return (TypeMirror) DocTrees.class.getMethod("getType", DocTreePath.class).invoke(docTrees, path); 164 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 165 | throw new RuntimeException(e); 166 | } 167 | } 168 | 169 | @Override 170 | public List getFirstSentence(List list) { 171 | return docTrees.getFirstSentence(list); 172 | } 173 | 174 | @Override 175 | public DocSourcePositions getSourcePositions() { 176 | return docTrees.getSourcePositions(); 177 | } 178 | 179 | @Override 180 | public void printMessage(Diagnostic.Kind kind, CharSequence msg, DocTree t, DocCommentTree c, CompilationUnitTree root) { 181 | docTrees.printMessage(kind, msg, t, c, root); 182 | } 183 | 184 | @Override 185 | public void setBreakIterator(BreakIterator breakiterator) { 186 | docTrees.setBreakIterator(breakiterator); 187 | } 188 | 189 | @Override 190 | public DocTreeFactory getDocTreeFactory() { 191 | return docTrees.getDocTreeFactory(); 192 | } 193 | 194 | 195 | public String getCharacters(EntityTree tree) { 196 | // FIXME placeholder implementation 197 | return tree.toString(); 198 | } 199 | 200 | @Override 201 | public Tree getTree(Element element) { 202 | return docTrees.getTree(element); 203 | } 204 | 205 | @Override 206 | public ClassTree getTree(TypeElement element) { 207 | return docTrees.getTree(element); 208 | } 209 | 210 | @Override 211 | public MethodTree getTree(ExecutableElement method) { 212 | return docTrees.getTree(method); 213 | } 214 | 215 | @Override 216 | public Tree getTree(Element e, AnnotationMirror a) { 217 | return docTrees.getTree(e, a); 218 | } 219 | 220 | @Override 221 | public Tree getTree(Element e, AnnotationMirror a, AnnotationValue v) { 222 | return docTrees.getTree(e, a, v); 223 | } 224 | 225 | @Override 226 | public TreePath getPath(CompilationUnitTree unit, Tree node) { 227 | return docTrees.getPath(unit, node); 228 | } 229 | 230 | @Override 231 | public TreePath getPath(Element e) { 232 | return docTrees.getPath(e); 233 | } 234 | 235 | @Override 236 | public TreePath getPath(Element e, AnnotationMirror a) { 237 | return docTrees.getPath(e, a); 238 | } 239 | 240 | @Override 241 | public TreePath getPath(Element e, AnnotationMirror a, AnnotationValue v) { 242 | return docTrees.getPath(e, a, v); 243 | } 244 | 245 | @Override 246 | public Element getElement(TreePath path) { 247 | return docTrees.getElement(path); 248 | } 249 | 250 | @Override 251 | public TypeMirror getTypeMirror(TreePath path) { 252 | return docTrees.getTypeMirror(path); 253 | } 254 | 255 | @Override 256 | public Scope getScope(TreePath path) { 257 | return docTrees.getScope(path); 258 | } 259 | 260 | @Override 261 | public boolean isAccessible(Scope scope, TypeElement type) { 262 | return docTrees.isAccessible(scope, type); 263 | } 264 | 265 | @Override 266 | public boolean isAccessible(Scope scope, Element member, DeclaredType type) { 267 | return docTrees.isAccessible(scope, member, type); 268 | } 269 | 270 | @Override 271 | public TypeMirror getOriginalType(ErrorType errorType) { 272 | return docTrees.getOriginalType(errorType); 273 | } 274 | 275 | @Override 276 | public void printMessage(Diagnostic.Kind kind, CharSequence msg, Tree t, CompilationUnitTree root) { 277 | docTrees.printMessage(kind, msg, t, root); 278 | } 279 | 280 | @Override 281 | public TypeMirror getLub(CatchTree tree) { 282 | return docTrees.getLub(tree); 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/AsciidocComment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import com.sun.tools.javac.parser.Tokens; 19 | 20 | class AsciidocComment implements Tokens.Comment { 21 | 22 | private final String asciidoc; 23 | private final Tokens.Comment comment; 24 | 25 | AsciidocComment(String asciidoc, Tokens.Comment comment) { 26 | this.asciidoc = asciidoc; 27 | this.comment = comment; 28 | } 29 | 30 | @Override 31 | public String getText() { 32 | return asciidoc; 33 | } 34 | 35 | @Override 36 | public int getSourcePos(int index) { 37 | // can we somehow map positions in the asciidoctor back to positions in the source javadoc? 38 | return comment.getSourcePos(0); 39 | } 40 | 41 | @Override 42 | public CommentStyle getStyle() { 43 | return comment.getStyle(); 44 | } 45 | 46 | @Override 47 | public boolean isDeprecated() { 48 | return comment.isDeprecated(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/AsciidocFileView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import javax.lang.model.element.Modifier; 19 | import javax.lang.model.element.NestingKind; 20 | import javax.tools.FileObject; 21 | import javax.tools.JavaFileObject; 22 | import java.io.ByteArrayInputStream; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.io.OutputStream; 26 | import java.io.Reader; 27 | import java.io.StringReader; 28 | import java.io.Writer; 29 | import java.net.URI; 30 | import java.net.URISyntaxException; 31 | import java.nio.charset.Charset; 32 | 33 | /** 34 | * Handles other documents like the overview. 35 | */ 36 | class AsciidocFileView implements JavaFileObject { 37 | 38 | private final AsciidoctorConverter converter; 39 | private final FileObject fileObject; 40 | private String renderedContents; 41 | 42 | AsciidocFileView(AsciidoctorConverter converter, FileObject fileObject) { 43 | this.converter = converter; 44 | this.fileObject = fileObject; 45 | } 46 | 47 | @Override 48 | public URI toUri() { 49 | try { 50 | return new URI(maskFileExtension(fileObject.toUri().toString())); 51 | } catch (URISyntaxException e) { 52 | throw new RuntimeException(e); 53 | } 54 | } 55 | 56 | @Override 57 | public String getName() { 58 | return maskFileExtension(fileObject.getName()); 59 | } 60 | 61 | private String maskFileExtension(String name) { 62 | if (isAsciidoctorFile(name)) { 63 | name = name.substring(0, name.lastIndexOf('.')) + ".html"; 64 | } 65 | return name; 66 | } 67 | 68 | private boolean isAsciidoctorFile(String name) { 69 | return name.endsWith(".adoc") || name.endsWith(".ad") || name.endsWith(".asciidoc") || name.endsWith(".txt"); 70 | } 71 | 72 | @Override 73 | public InputStream openInputStream() throws IOException { 74 | return new ByteArrayInputStream(getCharContent(true).getBytes(Charset.defaultCharset())); 75 | } 76 | 77 | @Override 78 | public OutputStream openOutputStream() throws IOException { 79 | return fileObject.openOutputStream(); 80 | } 81 | 82 | @Override 83 | public Reader openReader(boolean ignoreEncodingErrors) throws IOException { 84 | return new StringReader(getCharContent(ignoreEncodingErrors)); 85 | } 86 | 87 | @Override 88 | public String getCharContent(boolean ignoreEncodingErrors) throws IOException { 89 | if (renderedContents == null) { 90 | renderedContents = fileObject.getCharContent(ignoreEncodingErrors).toString(); 91 | if (isAsciidoctorFile(fileObject.getName())) { 92 | renderedContents = "" + converter.convert(renderedContents) + ""; 93 | } 94 | } 95 | return renderedContents; 96 | } 97 | 98 | @Override 99 | public Writer openWriter() throws IOException { 100 | return fileObject.openWriter(); 101 | } 102 | 103 | @Override 104 | public long getLastModified() { 105 | return fileObject.getLastModified(); 106 | } 107 | 108 | @Override 109 | public boolean delete() { 110 | return fileObject.delete(); 111 | } 112 | 113 | @Override 114 | public Kind getKind() { 115 | return ((JavaFileObject) fileObject).getKind(); 116 | } 117 | 118 | @Override 119 | public boolean isNameCompatible(String simpleName, Kind kind) { 120 | return ((JavaFileObject) fileObject).isNameCompatible(simpleName, kind); 121 | } 122 | 123 | @Override 124 | public NestingKind getNestingKind() { 125 | return ((JavaFileObject) fileObject).getNestingKind(); 126 | } 127 | 128 | @Override 129 | public Modifier getAccessLevel() { 130 | return ((JavaFileObject) fileObject).getAccessLevel(); 131 | } 132 | 133 | @SuppressWarnings("unchecked") 134 | T unwrap() { 135 | return (T) fileObject; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/Asciidoclet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import jdk.javadoc.doclet.Doclet; 19 | import jdk.javadoc.doclet.DocletEnvironment; 20 | import jdk.javadoc.doclet.Reporter; 21 | import jdk.javadoc.doclet.StandardDoclet; 22 | 23 | import javax.lang.model.SourceVersion; 24 | import java.util.Arrays; 25 | import java.util.HashSet; 26 | import java.util.Locale; 27 | import java.util.Set; 28 | 29 | /** 30 | * = Asciidoclet 31 | *

32 | * https://github.com/asciidoctor/asciidoclet[Asciidoclet] is a Javadoc Doclet 33 | * that uses https://asciidoctor.org[Asciidoctor] (via the 34 | * https://github.com/asciidoctor/asciidoctorj[Asciidoctor Java integration]) 35 | * to interpret https://asciidoc.org[AsciiDoc] markup within Javadoc comments. 36 | *

37 | * include::README.adoc[tags=usage] 38 | *

39 | * == Examples 40 | *

41 | * Custom attributes:: 42 | * `+{project_name}+`;; {project_name} 43 | * `+{project_desc}+`;; {project_desc} 44 | * `+{project_version}+`;; {project_version} 45 | *

46 | * Code block (with syntax highlighting added by CodeRay):: 47 | * + 48 | * [source,java] 49 | * -- 50 | * /** 51 | * * = Asciidoclet 52 | * * 53 | * * A Javadoc Doclet that uses https://asciidoctor.org[Asciidoctor] 54 | * * to render https://asciidoc.org[AsciiDoc] markup in Javadoc comments. 55 | * * 56 | * * @author https://github.com/johncarl81[John Ericksen] 57 | * *\/ 58 | * public class Asciidoclet extends Doclet { 59 | * private final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); // <1> 60 | * 61 | * @author https://github.com/johncarl81[John Ericksen] 62 | * @version {project_version} 63 | * @SuppressWarnings("UnusedDeclaration") public static boolean start(RootDoc rootDoc) { 64 | * new Asciidoclet().render(rootDoc); // <2> 65 | * return Standard.start(rootDoc); 66 | * } 67 | * } 68 | * -- 69 | * <1> Creates an instance of the Asciidoctor Java integration 70 | * <2> Runs Javadoc comment strings through Asciidoctor 71 | *

72 | * Inline code:: `code()` 73 | *

74 | * Headings:: 75 | * + 76 | * -- 77 | * [float] 78 | * = Heading 1 79 | *

80 | * [float] 81 | * == Heading 2 82 | *

83 | * [float] 84 | * === Heading 3 85 | *

86 | * [float] 87 | * ==== Heading 4 88 | *

89 | * [float] 90 | * ===== Heading 5 91 | * -- 92 | *

93 | * Links:: 94 | * Doc Writer + 95 | * https://asciidoc.org[AsciiDoc] is a lightweight markup language. + 96 | * Learn more about it at https://asciidoctor.org. + 97 | *

98 | * Bullets:: 99 | * + 100 | * -- 101 | * .Unnumbered 102 | * * bullet 103 | * * bullet 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 | * -- 120 | * + 121 | * -- 122 | * .Numbered 123 | * . bullet 124 | * . bullet 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 | * -- 139 | *

140 | * Tables:: 141 | * + 142 | * .An example table 143 | * |=== 144 | * |Column 1 |Column 2 |Column 3 145 | *

146 | * |1 147 | * |Item 1 148 | * |a 149 | *

150 | * |2 151 | * |Item 2 152 | * |b 153 | *

154 | * |3 155 | * |Item 3 156 | * |c 157 | * |=== 158 | *

159 | * Sidebar block:: 160 | * + 161 | * .Optional Title 162 | * **** 163 | * Usage: Notes in a sidebar, naturally. 164 | * **** 165 | *

166 | * Admonitions:: 167 | * + 168 | * IMPORTANT: Check this out! 169 | * @serial (or @ serialField or @ serialData) 170 | * @see Asciidoclet 171 | * @since 0.1.0 172 | */ 173 | public class Asciidoclet implements Doclet { 174 | 175 | private StandardDoclet standardDoclet; 176 | private DocletOptions docletOptions; 177 | private Stylesheets stylesheets; 178 | private Reporter reporter; 179 | 180 | /** 181 | * Creates a new {@link Asciidoclet} object. 182 | */ 183 | public Asciidoclet() { 184 | standardDoclet = new StandardDoclet(); 185 | } 186 | 187 | @Override 188 | public void init(Locale locale, Reporter reporter) { 189 | this.reporter = reporter; 190 | this.standardDoclet.init(locale, reporter); 191 | this.docletOptions = new DocletOptions(reporter); 192 | this.stylesheets = new Stylesheets(reporter); 193 | } 194 | 195 | @Override 196 | public String getName() { 197 | return "Asciidoclet"; 198 | } 199 | 200 | @Override 201 | public Set getSupportedOptions() { 202 | Set

111 | * The source is first cleaned by stripping any trailing space after an 112 | * end line (e.g., `"\n "`), which gets left behind by the Javadoc 113 | * processor. 114 | * 115 | * @param input AsciiDoc source 116 | * @param inline true to set doc_type to inline, null otherwise 117 | * @return content rendered by Asciidoctor 118 | */ 119 | private String convert(String input, boolean inline) { 120 | if (input.trim().isEmpty()) { 121 | return ""; 122 | } 123 | Options options = new AsciidoctorOptionsFactory(asciidoctor, reporter) 124 | .create(docletOptions, templates); 125 | // Setting doctype to null results in an NPE from asciidoctor. 126 | // the default value from the command line is "article". 127 | // https://docs.asciidoctor.org/asciidoctor/latest/cli/man1/asciidoctor/#options 128 | options.setDocType(inline ? 129 | INLINE_DOCTYPE : 130 | options.map().containsKey(Options.DOCTYPE) ? 131 | (String) options.map().get(Options.DOCTYPE) : 132 | "article"); 133 | 134 | return asciidoctor.convert(cleanJavadocInput(input), options); 135 | } 136 | 137 | static String cleanJavadocInput(String input) { 138 | return input.trim() 139 | .replaceAll("\n ", "\n") // Newline space to accommodate javadoc newlines. 140 | .replaceAll("\\{at}", "@") // {at} is translated into @. 141 | .replaceAll("\\{slash}", "/") // {slash} is translated into /. 142 | .replaceAll("(?m)^( *)\\*\\\\/$", "$1*/"); // Multi-line comment end tag is translated into */. 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/AsciidoctorFileManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import javax.tools.FileObject; 19 | import javax.tools.JavaFileObject; 20 | import javax.tools.StandardJavaFileManager; 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.nio.file.Path; 24 | import java.util.Collection; 25 | import java.util.Iterator; 26 | import java.util.ServiceLoader; 27 | import java.util.Set; 28 | import java.util.stream.StreamSupport; 29 | 30 | class AsciidoctorFileManager implements StandardJavaFileManager { 31 | 32 | private final AsciidoctorConverter converter; 33 | private final StandardJavaFileManager delegate; 34 | 35 | AsciidoctorFileManager(AsciidoctorConverter converter, StandardJavaFileManager delegate) { 36 | this.converter = converter; 37 | this.delegate = delegate; 38 | } 39 | 40 | @Override 41 | public boolean isSameFile(FileObject a, FileObject b) { 42 | return delegate.isSameFile(a, b); 43 | } 44 | 45 | @Override 46 | public Iterable getJavaFileObjectsFromFiles(Iterable files) { 47 | return wrap(delegate.getJavaFileObjectsFromFiles(files)); 48 | } 49 | 50 | @Override 51 | public Iterable getJavaFileObjectsFromPaths(Iterable paths) { 52 | return wrap(delegate.getJavaFileObjectsFromPaths(paths)); 53 | } 54 | 55 | @Override 56 | public Iterable getJavaFileObjects(File... files) { 57 | return wrap(delegate.getJavaFileObjects(files)); 58 | } 59 | 60 | @Override 61 | public Iterable getJavaFileObjects(Path... paths) { 62 | return wrap(delegate.getJavaFileObjects(paths)); 63 | } 64 | 65 | @Override 66 | public Iterable getJavaFileObjectsFromStrings(Iterable names) { 67 | return wrap(delegate.getJavaFileObjectsFromStrings(names)); 68 | } 69 | 70 | @Override 71 | public Iterable getJavaFileObjects(String... names) { 72 | return wrap(delegate.getJavaFileObjects(names)); 73 | } 74 | 75 | @Override 76 | public void setLocation(Location location, Iterable files) throws IOException { 77 | delegate.setLocation(location, files); 78 | } 79 | 80 | @Override 81 | public void setLocationFromPaths(Location location, Collection paths) throws IOException { 82 | delegate.setLocationFromPaths(location, paths); 83 | } 84 | 85 | @Override 86 | public void setLocationForModule(Location location, String moduleName, Collection paths) throws IOException { 87 | delegate.setLocationForModule(location, moduleName, paths); 88 | } 89 | 90 | @Override 91 | public Iterable getLocation(Location location) { 92 | return delegate.getLocation(location); 93 | } 94 | 95 | @Override 96 | public Iterable getLocationAsPaths(Location location) { 97 | return delegate.getLocationAsPaths(location); 98 | } 99 | 100 | @Override 101 | public Path asPath(FileObject file) { 102 | return delegate.asPath(unwrap(file)); 103 | } 104 | 105 | @Override 106 | public void setPathFactory(PathFactory f) { 107 | delegate.setPathFactory(f); 108 | } 109 | 110 | @Override 111 | public ClassLoader getClassLoader(Location location) { 112 | return delegate.getClassLoader(location); 113 | } 114 | 115 | @Override 116 | public Iterable list(Location location, String packageName, Set kinds, boolean recurse) throws IOException { 117 | return wrap(delegate.list(location, packageName, kinds, recurse)); 118 | } 119 | 120 | @Override 121 | public String inferBinaryName(Location location, JavaFileObject file) { 122 | return delegate.inferBinaryName(location, unwrap(file)); 123 | } 124 | 125 | @Override 126 | public boolean handleOption(String current, Iterator remaining) { 127 | return delegate.handleOption(current, remaining); 128 | } 129 | 130 | @Override 131 | public boolean hasLocation(Location location) { 132 | return delegate.hasLocation(location); 133 | } 134 | 135 | @Override 136 | public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException { 137 | return wrap(delegate.getJavaFileForInput(location, className, kind)); 138 | } 139 | 140 | @Override 141 | public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { 142 | return wrap(delegate.getJavaFileForOutput(location, className, kind, unwrap(sibling))); 143 | } 144 | 145 | @Override 146 | public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { 147 | return wrap(delegate.getFileForInput(location, packageName, relativeName)); 148 | } 149 | 150 | @Override 151 | public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { 152 | return wrap(delegate.getFileForOutput(location, packageName, relativeName, unwrap(sibling))); 153 | } 154 | 155 | @Override 156 | public void flush() throws IOException { 157 | delegate.flush(); 158 | } 159 | 160 | @Override 161 | public void close() throws IOException { 162 | delegate.close(); 163 | } 164 | 165 | @Override 166 | public Location getLocationForModule(Location location, String moduleName) throws IOException { 167 | return delegate.getLocationForModule(location, moduleName); 168 | } 169 | 170 | @Override 171 | public Location getLocationForModule(Location location, JavaFileObject fo) throws IOException { 172 | return delegate.getLocationForModule(location, unwrap(fo)); 173 | } 174 | 175 | @Override 176 | public ServiceLoader getServiceLoader(Location location, Class service) throws IOException { 177 | return delegate.getServiceLoader(location, service); 178 | } 179 | 180 | @Override 181 | public String inferModuleName(Location location) throws IOException { 182 | return delegate.inferModuleName(location); 183 | } 184 | 185 | @Override 186 | public Iterable> listLocationsForModules(Location location) throws IOException { 187 | return delegate.listLocationsForModules(location); 188 | } 189 | 190 | @Override 191 | public boolean contains(Location location, FileObject fo) throws IOException { 192 | return delegate.contains(location, unwrap(fo)); 193 | } 194 | 195 | @Override 196 | public int isSupportedOption(String option) { 197 | return delegate.isSupportedOption(option); 198 | } 199 | 200 | @SuppressWarnings("unchecked") 201 | private T wrap(T fo) { 202 | return (T) new AsciidocFileView(converter, fo); 203 | } 204 | 205 | private Iterable wrap(Iterable fos) { 206 | return () -> StreamSupport.stream(fos.spliterator(), false).map(this::wrap).iterator(); 207 | } 208 | 209 | private T unwrap(T fo) { 210 | if (fo instanceof AsciidocFileView) { 211 | return ((AsciidocFileView) fo).unwrap(); 212 | } 213 | return fo; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/AsciidoctorFilteredEnvironment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import com.sun.source.util.DocTrees; 19 | import jdk.javadoc.doclet.DocletEnvironment; 20 | import jdk.javadoc.internal.tool.DocEnvImpl; 21 | 22 | import javax.tools.JavaFileManager; 23 | import javax.tools.StandardJavaFileManager; 24 | 25 | /** 26 | * An operating environment defined for AsciiDoclet. 27 | */ 28 | public class AsciidoctorFilteredEnvironment 29 | extends DocEnvImpl 30 | implements DocletEnvironment, AutoCloseable { 31 | 32 | private final StandardJavaFileManager fileManager; 33 | private final AsciiDocTrees asciiDocTrees; 34 | 35 | AsciidoctorFilteredEnvironment(DocletEnvironment environment, AsciidoctorConverter converter) { 36 | super(((DocEnvImpl) environment).toolEnv, ((DocEnvImpl) environment).etable); 37 | this.fileManager = new AsciidoctorFileManager(converter, (StandardJavaFileManager) environment.getJavaFileManager()); 38 | this.asciiDocTrees = new AsciiDocTrees(converter, fileManager, environment.getDocTrees()); 39 | } 40 | 41 | @Override 42 | public JavaFileManager getJavaFileManager() { 43 | return fileManager; 44 | } 45 | 46 | @Override 47 | public DocTrees getDocTrees() { 48 | return asciiDocTrees; 49 | } 50 | 51 | @Override 52 | public void close() { 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/AsciidoctorOptionsFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import jdk.javadoc.doclet.Reporter; 19 | import org.asciidoctor.Asciidoctor; 20 | import org.asciidoctor.Attributes; 21 | import org.asciidoctor.AttributesBuilder; 22 | import org.asciidoctor.Options; 23 | import org.asciidoctor.OptionsBuilder; 24 | import org.asciidoctor.SafeMode; 25 | import org.asciidoctor.extension.RubyExtensionRegistry; 26 | 27 | /** 28 | * Asciidoctor Options Factory. 29 | * 30 | * @since 2.0.0 31 | */ 32 | class AsciidoctorOptionsFactory { 33 | 34 | private static final String DEFAULT_BACKEND = "html5"; 35 | 36 | private final Asciidoctor asciidoctor; 37 | private final Reporter reporter; 38 | 39 | AsciidoctorOptionsFactory(Asciidoctor asciidoctor, Reporter reporter) { 40 | this.asciidoctor = asciidoctor; 41 | this.reporter = reporter; 42 | } 43 | 44 | Options create(DocletOptions docletOptions, OutputTemplates templates) { 45 | final OptionsBuilder opts = defaultOptions(); 46 | if (docletOptions.baseDir().isPresent()) { 47 | opts.baseDir(docletOptions.baseDir().get()); 48 | } 49 | if (templates != null) { 50 | opts.templateDir(templates.templateDir().toFile()); 51 | } 52 | 53 | opts.attributes(buildAttributes(docletOptions)); 54 | if (docletOptions.requires().size() > 0) { 55 | RubyExtensionRegistry rubyExtensionRegistry = asciidoctor.rubyExtensionRegistry(); 56 | for (String require : docletOptions.requires()) { 57 | rubyExtensionRegistry.requireLibrary(require); 58 | } 59 | } 60 | return opts.get(); 61 | } 62 | 63 | private Attributes buildAttributes(DocletOptions docletOptions) { 64 | return defaultAttributes() 65 | .attributes(new AttributesLoader(asciidoctor, docletOptions, reporter).load()) 66 | .get(); 67 | } 68 | 69 | private static OptionsBuilder defaultOptions() { 70 | return Options.builder() 71 | .safe(SafeMode.SAFE) 72 | .backend(DEFAULT_BACKEND); 73 | } 74 | 75 | private static AttributesBuilder defaultAttributes() { 76 | return org.asciidoctor.Attributes.builder() 77 | .attribute("at", "@") 78 | .attribute("slash", "/") 79 | .attribute("icons", null) 80 | .attribute("idprefix", "") 81 | .attribute("idseparator", "-") 82 | .attribute("javadoc", "") 83 | .attribute("showtitle", true) 84 | .attribute("source-highlighter", "coderay") 85 | .attribute("coderay-css", "class") 86 | .attribute("env-asciidoclet") 87 | .attribute("env", "asciidoclet"); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/AttributesLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import jdk.javadoc.doclet.Reporter; 19 | import org.asciidoctor.Asciidoctor; 20 | import org.asciidoctor.Attributes; 21 | import org.asciidoctor.Options; 22 | import org.asciidoctor.OptionsBuilder; 23 | import org.asciidoctor.SafeMode; 24 | 25 | import javax.tools.Diagnostic; 26 | import java.io.File; 27 | import java.io.Reader; 28 | import java.nio.file.Files; 29 | import java.util.HashSet; 30 | import java.util.List; 31 | import java.util.Map; 32 | import java.util.Optional; 33 | import java.util.Scanner; 34 | import java.util.Set; 35 | 36 | class AttributesLoader { 37 | 38 | private final Asciidoctor asciidoctor; 39 | private final DocletOptions docletOptions; 40 | private final Reporter reporter; 41 | 42 | AttributesLoader(Asciidoctor asciidoctor, DocletOptions docletOptions, Reporter reporter) { 43 | this.asciidoctor = asciidoctor; 44 | this.docletOptions = docletOptions; 45 | this.reporter = reporter; 46 | } 47 | 48 | Map load() { 49 | List attributeArgs = docletOptions.attributes(); 50 | Set unset = getUnsetAttributes(attributeArgs); 51 | 52 | // Parse command-line attrs first, if any 53 | Map cmdlineAttrs = parseCmdLineAttributes(attributeArgs); 54 | 55 | // Parse the attributes file, passing in any command-line attrs already set 56 | Map attrs = parseAttributesFile(docletOptions.attributesFile(), cmdlineAttrs); 57 | 58 | // Remove any attributes that were set in the file but removed by the -attributes option 59 | attrs.keySet().removeAll(unset); 60 | 61 | // Put unset attribute names back into the map as "key!", so Asciidoctor will unset 62 | // those attributes in the document. 63 | for (String key : unset) { 64 | attrs.put(key + "!", ""); 65 | } 66 | 67 | return attrs; 68 | } 69 | 70 | private Map parseCmdLineAttributes(List attributeArgs) { 71 | return new Attributes(attributeArgs.toArray(new String[0])).map(); 72 | } 73 | 74 | private Map parseAttributesFile(Optional attrsFile, Map cmdlineAttrs) { 75 | if (attrsFile.isPresent()) { 76 | try (Reader reader = Files.newBufferedReader(attrsFile.get().toPath(), docletOptions.encoding())) { 77 | return parseAttributes(reader, cmdlineAttrs); 78 | } catch (Exception e) { 79 | reporter.print(Diagnostic.Kind.WARNING, "Cannot read attributes file: " + e); 80 | } 81 | } 82 | return cmdlineAttrs; 83 | } 84 | 85 | private Map parseAttributes(Reader in, Map existingAttrs) { 86 | OptionsBuilder options = Options.builder() 87 | .safe(SafeMode.SAFE) 88 | .attributes(existingAttrs) 89 | .parseHeaderOnly(true); 90 | if (docletOptions.baseDir().isPresent()) { 91 | options.baseDir(docletOptions.baseDir().get()); 92 | } 93 | 94 | return asciidoctor.load(read(in), options.build()).getAttributes(); 95 | } 96 | 97 | public static String read(Reader reader) { 98 | try (Scanner scanner = new Scanner(reader).useDelimiter("\\A")) { 99 | return scanner.next(); 100 | } 101 | } 102 | 103 | private Set getUnsetAttributes(List args) { 104 | Set removed = new HashSet<>(); 105 | for (String arg : args) { 106 | String key = getKey(arg); 107 | if (key.startsWith("!") || key.endsWith("!")) { 108 | removed.add(normalizeAttrName(key)); 109 | } 110 | } 111 | return Set.copyOf(removed); 112 | } 113 | 114 | private String getKey(String arg) { 115 | int idx = arg.indexOf('='); 116 | if (idx == 0) { 117 | throw new IllegalArgumentException("Invalid attribute arg: \"" + arg + "\""); 118 | } 119 | return idx == -1 ? arg : arg.substring(0, idx); 120 | } 121 | 122 | // remove non-word chars in name as asciidoctor would 123 | private String normalizeAttrName(String name) { 124 | return name.replaceAll("\\W", "").toLowerCase(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/DocletOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import jdk.javadoc.doclet.Reporter; 19 | 20 | import java.io.File; 21 | import java.nio.charset.Charset; 22 | import java.util.ArrayList; 23 | import java.util.Arrays; 24 | import java.util.List; 25 | import java.util.Optional; 26 | import java.util.stream.Stream; 27 | 28 | import static javax.tools.Diagnostic.Kind.WARNING; 29 | 30 | /** 31 | * Provides an interface to the doclet options we are interested in. 32 | */ 33 | public class DocletOptions { 34 | 35 | private final Reporter reporter; 36 | 37 | private Charset encoding; 38 | private File basedir; 39 | private File stylesheet; 40 | private File attributesFile; 41 | private List attributes; 42 | private String gemPath; 43 | private List requires; 44 | 45 | /** 46 | * Creates an {@link DocletOptions} object with a given {@link Reporter} object. 47 | * 48 | * @param reporter A {@link Reporter} object with which a new object is created. 49 | */ 50 | public DocletOptions(Reporter reporter) { 51 | this.reporter = reporter; 52 | encoding = Charset.defaultCharset(); 53 | attributes = new ArrayList<>(); 54 | requires = new ArrayList<>(); 55 | } 56 | 57 | void collect(AsciidocletOptions option, List list) { 58 | switch (option) { 59 | case ENCODING: 60 | encoding = Charset.forName(list.get(0)); 61 | break; 62 | case BASEDIR: 63 | basedir = new File(list.get(0)); 64 | break; 65 | case STYLESHEET: 66 | stylesheet = new File(list.get(0)); 67 | break; 68 | case ATTRIBUTE: 69 | case ATTRIBUTE_LONG: 70 | splitTrimStream(list).forEach(attributes::add); 71 | break; 72 | case ATTRIBUTES_FILE: 73 | attributesFile = new File(list.get(0)); 74 | break; 75 | case GEM_PATH: 76 | gemPath = list.get(0); 77 | break; 78 | case REQUIRE: 79 | case REQUIRE_LONG: 80 | splitTrimStream(list).forEach(requires::add); 81 | break; 82 | } 83 | } 84 | 85 | private Stream splitTrimStream(List list) { 86 | return list.stream() 87 | .flatMap(s -> Arrays.stream(s.split("\\s*,\\s*"))) 88 | .map(String::trim) 89 | .filter(s -> !s.isEmpty()); 90 | } 91 | 92 | void validate() { 93 | if (baseDir().isEmpty()) { 94 | printWarning(AsciidocletOptions.BASEDIR + " must be present for includes or file reference features to work properly"); 95 | } 96 | 97 | Optional attrsFile = attributesFile(); 98 | if (attrsFile.isPresent() && !attrsFile.get().canRead()) { 99 | printWarning("Cannot read attributes file " + attrsFile.get()); 100 | } 101 | } 102 | 103 | private void printWarning(String message) { 104 | reporter.print(WARNING, message); 105 | } 106 | 107 | Optional stylesheet() { 108 | return Optional.ofNullable(stylesheet); 109 | } 110 | 111 | Optional baseDir() { 112 | return Optional.ofNullable(basedir); 113 | } 114 | 115 | Charset encoding() { 116 | return encoding; 117 | } 118 | 119 | List attributes() { 120 | return attributes; 121 | } 122 | 123 | Optional attributesFile() { 124 | if (attributesFile == null) { 125 | return Optional.empty(); 126 | } 127 | if (!attributesFile.isAbsolute() && baseDir().isPresent()) { 128 | return Optional.of(new File(baseDir().get(), attributesFile.getPath())); 129 | } 130 | return Optional.of(attributesFile); 131 | } 132 | 133 | String gemPath() { 134 | return gemPath; 135 | } 136 | 137 | List requires() { 138 | return requires; 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/JavadocParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Map; 21 | import java.util.Objects; 22 | import java.util.regex.Matcher; 23 | import java.util.regex.Pattern; 24 | 25 | import static java.util.regex.Pattern.MULTILINE; 26 | import static java.util.regex.Pattern.compile; 27 | import static java.util.regex.Pattern.quote; 28 | import static java.util.stream.Collectors.joining; 29 | import static java.util.stream.Stream.of; 30 | 31 | /** 32 | * Breaks the Javadoc comment string into the main comment text and its tags. 33 | * This parser is AsciiDoc aware, and will avoid parsing tags inside code blocks. 34 | */ 35 | class JavadocParser { 36 | 37 | private static final String[] DELIMITERS = {"====", "////", "```", "----", "....", "--", "____", "****", "|==="}; 38 | private static final Pattern DELIMITER_OR_TAG = 39 | compile("(^\\s*)((" + of(DELIMITERS).map(Pattern::quote).collect(joining(")|(")) + ")|@)", MULTILINE); 40 | @SuppressWarnings("unchecked") 41 | private static final Map DELIMITER_PATTERNS = Map.ofEntries(of(DELIMITERS) 42 | .map(k -> Map.entry(k, compile("(^\\s*)" + quote(k), MULTILINE))).toArray(Map.Entry[]::new)); 43 | private static final Pattern TAG_NAME = compile("\\G(\\w+)\\s*"); 44 | 45 | static class Tag { 46 | // TODO Make immutable 47 | String tagName; 48 | String tagText; 49 | 50 | Tag(String tagName, String tagText) { 51 | this.tagName = tagName; 52 | this.tagText = tagText; 53 | } 54 | 55 | @Override 56 | public boolean equals(Object o) { 57 | if (this == o) { 58 | return true; 59 | } 60 | if (o == null || getClass() != o.getClass()) { 61 | return false; 62 | } 63 | Tag tag = (Tag) o; 64 | return tagName.equals(tag.tagName) && Objects.equals(tagText, tag.tagText); 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | return Objects.hash(tagName, tagText); 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return "Tag{" + "tagName='" + tagName + '\'' + ", tagText='" + tagText + '\'' + '}'; 75 | } 76 | } 77 | 78 | /** 79 | * Sorted comments with different tags. 80 | */ 81 | private final List tags = new ArrayList<>(); 82 | 83 | /** 84 | * The body of the javadoc text, without the tags. 85 | */ 86 | private String commentBody; 87 | 88 | /** 89 | * Create a JavadocParser the Javadoc comment string. 90 | * 91 | * @param commentString Javadoc string 92 | */ 93 | public static JavadocParser parse(String commentString) { 94 | final JavadocParser javadocParser = new JavadocParser(); 95 | javadocParser.parseComment(commentString); 96 | return javadocParser; 97 | } 98 | 99 | private void parseComment(String commentString) { 100 | // We parse the text through a state machine that roughly looks like this: 101 | // 102 | // javadoc -> body tag* 103 | // body -> (text | block)* 104 | // block -> delim(1) text $1 105 | // delim -> '====' | '////' | '```' | '----' | '....' | '--' | '++++' | '____' | '****' | '|===' 106 | // tag -> tagName (\s+ tagText)? 107 | // tagText -> body 108 | // 109 | // There is an additional restriction that tags can only start at the beginning of a line, 110 | // and block delimiters must stand alone on their lines. 111 | // This restriction removes a lot of otherwise subtle edge cases from the parsing. 112 | 113 | Matcher matcher = DELIMITER_OR_TAG.matcher(commentString); 114 | int captureSince = 0; 115 | while (matcher.find()) { 116 | String group = matcher.group(2); 117 | if (group.equals("@")) { 118 | int startOfMatch = matcher.start(); 119 | captureComponent(commentString, captureSince, startOfMatch); 120 | matcher.usePattern(TAG_NAME); 121 | if (matcher.find()) { 122 | Tag tag = new Tag(group + matcher.group(1), null); 123 | tags.add(tag); 124 | captureSince = matcher.end(); 125 | } 126 | matcher.usePattern(DELIMITER_OR_TAG); 127 | } else { 128 | matcher.usePattern(DELIMITER_PATTERNS.get(group)); 129 | matcher.find(); 130 | matcher.usePattern(DELIMITER_OR_TAG); 131 | } 132 | } 133 | captureComponent(commentString, captureSince, commentString.length()); 134 | } 135 | 136 | private void captureComponent(String commentString, int captureSince, int endOfCapture) { 137 | String component = commentString.substring(captureSince, endOfCapture).trim(); 138 | if (commentBody == null) { 139 | commentBody = component; 140 | } else { 141 | tags.get(tags.size() - 1).tagText = component; 142 | } 143 | } 144 | 145 | /** 146 | * Return the text body of the comment, without the tags. 147 | */ 148 | String getCommentBody() { 149 | return commentBody; 150 | } 151 | 152 | /** 153 | * Returns all the parsed tags. 154 | */ 155 | List tags() { 156 | return tags; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/LazyDocCommentTableProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import com.sun.tools.javac.parser.LazyDocCommentTable; 19 | import com.sun.tools.javac.parser.Tokens.Comment; 20 | import com.sun.tools.javac.tree.DocCommentTable; 21 | 22 | import java.lang.reflect.Constructor; 23 | import java.lang.reflect.Field; 24 | import java.util.Map; 25 | import java.util.function.Function; 26 | 27 | class LazyDocCommentTableProcessor { 28 | static final Function COMMENT_FIELD_EXTRACTOR = commentFieldExtractor(); 29 | static final Function COMMENT_INSTANTIATOR = commentInstantiator(); 30 | public static final Field LAZY_DOC_COMMENT_TABLE_TABLE_FIELD = getLazyDocCommentTable_TableField(); 31 | 32 | 33 | @SuppressWarnings({"unchecked", "rawtypes"}) 34 | static void processComments(DocCommentTable table, Function commentMapper) { 35 | // table can be non-LazyDocCommentTable instance only for `default constructors` as far as I know now. 36 | if (table instanceof LazyDocCommentTable) { 37 | // Use heckin' raw-types because LazyDocCommentTable.Entry has private access, so we 38 | // cannot statically express its type here. 39 | //System.err.println("THEN:" + LazyDocCommentTableProcessor.class + ":processComments:" + System.identityHashCode(table)); 40 | Map map = tableFieldValueOf(table); 41 | Function converter = COMMENT_FIELD_EXTRACTOR.andThen(commentMapper).andThen(COMMENT_INSTANTIATOR); 42 | map.replaceAll((tree, entry) -> converter.apply(entry)); 43 | } 44 | } 45 | 46 | @SuppressWarnings("rawtypes") 47 | private static Map tableFieldValueOf(DocCommentTable table) { 48 | try { 49 | return (Map) LAZY_DOC_COMMENT_TABLE_TABLE_FIELD.get(table); 50 | } catch (IllegalAccessException e) { 51 | throw new RuntimeException(e); 52 | } 53 | } 54 | 55 | private static Function commentFieldExtractor() { 56 | Field entryClassCommentField = getLazyDocCommentTable$EntryClassCommentField(getLazyDocCommentTable$EntryClass()); 57 | return entry -> { 58 | try { 59 | return (Comment) entryClassCommentField.get(entry); 60 | } catch (Exception e) { 61 | throw new RuntimeException(e); 62 | } 63 | }; 64 | } 65 | 66 | private static Function commentInstantiator() { 67 | @SuppressWarnings("rawtypes") Constructor entryClassConstructor = getLazyDocCommentTable$EntryClassConstructor(); 68 | return comment -> { 69 | try { 70 | return entryClassConstructor.newInstance(comment); 71 | } catch (Exception e) { 72 | throw new RuntimeException(e); 73 | } 74 | }; 75 | } 76 | 77 | private static Field getLazyDocCommentTable$EntryClassCommentField(Class entryClass) { 78 | try { 79 | Field commentField = entryClass.getDeclaredField("comment"); 80 | commentField.setAccessible(true); 81 | return commentField; 82 | } catch (NoSuchFieldException e) { 83 | throw new RuntimeException(e); 84 | } 85 | } 86 | 87 | private static Constructor getLazyDocCommentTable$EntryClassConstructor() { 88 | try { 89 | Constructor ctor = getLazyDocCommentTable$EntryClass().getDeclaredConstructor(Comment.class); 90 | ctor.setAccessible(true); 91 | return ctor; 92 | } catch (NoSuchMethodException e) { 93 | throw new RuntimeException(e); 94 | } 95 | } 96 | 97 | private static Class getLazyDocCommentTable$EntryClass() { 98 | try { 99 | return Class.forName("com.sun.tools.javac.parser.LazyDocCommentTable$Entry"); 100 | } catch (ClassNotFoundException e) { 101 | throw new RuntimeException(e); 102 | } 103 | } 104 | 105 | private static Field getLazyDocCommentTable_TableField() { 106 | try { 107 | Field tableField = LazyDocCommentTable.class.getDeclaredField("table"); 108 | tableField.setAccessible(true); 109 | return tableField; 110 | } catch (NoSuchFieldException e) { 111 | throw new RuntimeException(e); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/OptionProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import jdk.javadoc.doclet.Doclet; 19 | 20 | import java.util.List; 21 | 22 | class OptionProcessor implements Doclet.Option { 23 | 24 | private final AsciidocletOptions prototype; 25 | private final DocletOptions collector; 26 | 27 | OptionProcessor(AsciidocletOptions prototype, DocletOptions collector) { 28 | this.prototype = prototype; 29 | this.collector = collector; 30 | } 31 | 32 | @Override 33 | public int getArgumentCount() { 34 | return prototype.getArgumentCount(); 35 | } 36 | 37 | @Override 38 | public String getDescription() { 39 | return prototype.getDescription(); 40 | } 41 | 42 | @Override 43 | public Kind getKind() { 44 | return prototype.getKind(); 45 | } 46 | 47 | @Override 48 | public List getNames() { 49 | return prototype.getNames(); 50 | } 51 | 52 | @Override 53 | public String getParameters() { 54 | return prototype.getParameters(); 55 | } 56 | 57 | @Override 58 | public boolean process(String option, List arguments) { 59 | collector.collect(prototype, arguments); 60 | return true; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/OutputTemplates.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import jdk.javadoc.doclet.Reporter; 19 | 20 | import javax.tools.Diagnostic; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.OutputStream; 24 | import java.io.UncheckedIOException; 25 | import java.nio.file.Files; 26 | import java.nio.file.Path; 27 | 28 | /** 29 | * Sets up a temporary directory containing output templates for use by Asciidoctor. 30 | */ 31 | class OutputTemplates { 32 | 33 | private static final String[] TEMPLATE_NAMES = new String[]{"section.html.haml", "paragraph.html.haml"}; 34 | 35 | private final Path templateDir; 36 | 37 | private OutputTemplates(Path templateDir) { 38 | this.templateDir = templateDir; 39 | } 40 | 41 | static OutputTemplates create(Reporter reporter) { 42 | final Path dir = prepareTemplateDir(reporter); 43 | return dir != null ? new OutputTemplates(dir) : null; 44 | } 45 | 46 | Path templateDir() { 47 | return templateDir; 48 | } 49 | 50 | /** 51 | * Creates and returns a directory in OS's temps path holding Asciidoctor 52 | * templates during conversion. 53 | * 54 | * @param reporter doclet {@link Reporter}. 55 | * @return Path to templates, or null if it could not be created. 56 | */ 57 | private static Path prepareTemplateDir(Reporter reporter) { 58 | // copy our template resources to the templateDir so Asciidoctor can use them. 59 | try { 60 | final Path templateDir = Files.createTempDirectory("asciidoclet"); 61 | for (String templateName : TEMPLATE_NAMES) { 62 | prepareTemplate(templateDir, templateName); 63 | } 64 | return templateDir; 65 | } catch (IOException e) { 66 | reporter.print(Diagnostic.Kind.WARNING, "Failed to prepare templates: " + e.getLocalizedMessage()); 67 | return null; 68 | } 69 | } 70 | 71 | /** 72 | * Copies Asciidoctor templates into a temporal location. 73 | * First, attempts to locate templates in the Java module, then attempts 74 | * direct Classpath search. This is to ensure it works in both test, and 75 | * shaded JAR. 76 | * 77 | * @param templateDir path where to copy the templates 78 | * @param template Asciidoctor template name 79 | */ 80 | private static void prepareTemplate(Path templateDir, String template) throws IOException { 81 | final String templatePath = "templates/" + template; 82 | final InputStream input = ModuleLayer.boot() 83 | .findModule("asciidoclet") 84 | .map(module -> getResourceAsStream(module, templatePath)) 85 | .orElseGet(() -> OutputTemplates.class.getClassLoader().getResourceAsStream(templatePath)); 86 | 87 | if (input == null) { 88 | throw new IOException("Could not find template " + template); 89 | } 90 | final Path path = templateDir.resolve(template); 91 | try (OutputStream output = Files.newOutputStream(path)) { 92 | input.transferTo(output); 93 | } finally { 94 | input.close(); 95 | } 96 | } 97 | 98 | private static InputStream getResourceAsStream(Module module, String path) { 99 | try { 100 | return module.getResourceAsStream(path); 101 | } catch (IOException e) { 102 | throw new UncheckedIOException(e); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/Stylesheets.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import jdk.javadoc.doclet.DocletEnvironment; 19 | import jdk.javadoc.doclet.Reporter; 20 | 21 | import javax.tools.Diagnostic; 22 | import javax.tools.DocumentationTool; 23 | import javax.tools.JavaFileManager; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.io.OutputStream; 27 | import java.util.regex.Matcher; 28 | import java.util.regex.Pattern; 29 | 30 | /** 31 | * Responsible for copying the appropriate stylesheet to the javadoc 32 | * output directory. 33 | */ 34 | public class Stylesheets { 35 | 36 | static final String JAVA_STYLESHEET_FORMAT = "stylesheet%s.css"; 37 | static final String JAVA11_STYLESHEET = String.format(JAVA_STYLESHEET_FORMAT, "11"); 38 | 39 | private static final String CODERAY_STYLESHEET = "coderay-asciidoctor.css"; 40 | private static final String OUTPUT_STYLESHEET = "stylesheet.css"; 41 | 42 | private final Reporter errorReporter; 43 | 44 | Stylesheets(Reporter errorReporter) { 45 | this.errorReporter = errorReporter; 46 | } 47 | 48 | /** 49 | * Copies an {@link DocletEnvironment} to this object. 50 | * @param environment An environment to be copied to this object. 51 | * @return `true` if successfully copied. `false` otherwise. 52 | */ 53 | public boolean copy(DocletEnvironment environment) { 54 | String stylesheet = selectStylesheet(System.getProperty("java.version")); 55 | JavaFileManager fm = environment.getJavaFileManager(); 56 | try (InputStream stylesheetIn = getResource(stylesheet); 57 | InputStream coderayStylesheetIn = getResource(CODERAY_STYLESHEET); 58 | OutputStream stylesheetOut = openOutputStream(fm, OUTPUT_STYLESHEET); 59 | OutputStream coderayStylesheetOut = openOutputStream(fm, CODERAY_STYLESHEET)) { 60 | stylesheetIn.transferTo(stylesheetOut); 61 | coderayStylesheetIn.transferTo(coderayStylesheetOut); 62 | return true; 63 | } catch (IOException e) { 64 | errorReporter.print(Diagnostic.Kind.ERROR, e.getLocalizedMessage()); 65 | return false; 66 | } 67 | } 68 | 69 | private OutputStream openOutputStream(JavaFileManager fm, String filename) throws IOException { 70 | return fm.getFileForOutput(DocumentationTool.Location.DOCUMENTATION_OUTPUT, "", filename, null).openOutputStream(); 71 | } 72 | 73 | private InputStream getResource(String name) throws IOException { 74 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 75 | if (loader == null) { 76 | loader = Stylesheets.class.getClassLoader(); 77 | } 78 | InputStream stream = loader.getResourceAsStream(name); 79 | if (stream != null) { 80 | return stream; 81 | } 82 | 83 | Module module = Stylesheets.class.getModule(); 84 | if (module != null) { 85 | stream = module.getResourceAsStream(name); 86 | if (stream != null) { 87 | return stream; 88 | } 89 | } 90 | 91 | throw new IllegalArgumentException("No such resource: " + name); 92 | } 93 | 94 | String selectStylesheet(String javaVersion) { 95 | String ret; 96 | Matcher m = Pattern.compile("^([0-9]+)(\\.)?.*").matcher(javaVersion); 97 | if (m.matches()) { 98 | int selectedJavaMajorVersion = 11; 99 | // It is safe to do parseInt since it is already ensured an integer parsable string by the regex 100 | int javaMajorVersionAsInt = Integer.parseInt(m.group(1)); 101 | // In what version of Java, the stylesheet design was changed? 12, 13, 14? 102 | // The threshold 17 should be changed based on it. 103 | // Also, the filename stylesheet17.css should also be updated accordingly. 104 | if (11 <= javaMajorVersionAsInt && javaMajorVersionAsInt < 17 ) 105 | selectedJavaMajorVersion = 11; 106 | else if (17 <= javaMajorVersionAsInt) 107 | selectedJavaMajorVersion = 17; 108 | else 109 | errorReporter.print(Diagnostic.Kind.WARNING, "Unrecognized Java version " + javaVersion + ", using Java " + selectedJavaMajorVersion + " stylesheet"); 110 | ret = String.format(JAVA_STYLESHEET_FORMAT, selectedJavaMajorVersion); 111 | } else { 112 | ret = JAVA11_STYLESHEET; 113 | errorReporter.print(Diagnostic.Kind.WARNING, "Unrecognizable Java version " + javaVersion + ", using Java 11 stylesheet"); 114 | } 115 | return ret; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/asciidoctor/asciidoclet/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | * = Asciidoclet 18 | * 19 | * https://github.com/asciidoctor/asciidoclet[Asciidoclet] is a Javadoc Doclet 20 | * that uses https://asciidoctor.org[Asciidoctor] (via the 21 | * https://github.com/asciidoctor/asciidoctorj[Asciidoctor Java integration]) 22 | * to interpret https://asciidoc.org[AsciiDoc] markup within Javadoc comments. 23 | * 24 | * == Usage 25 | * 26 | * Asciidoclet may be used via a custom doclet in the maven-javadoc-plugin: 27 | * 28 | * [source,xml] 29 | * ---- 30 | * 31 | * org.apache.maven.plugins 32 | * maven-javadoc-plugin 33 | * 3.6.3 34 | * 35 | * 11 36 | * org.asciidoctor.asciidoclet.Asciidoclet 37 | * 38 | * org.asciidoctor 39 | * asciidoclet 40 | * ${asciidoclet.version} 41 | * 42 | * 43 | * 44 | * ---- 45 | * 46 | * == Examples 47 | * 48 | * Code block (with syntax highlighting added by CodeRay):: 49 | * + 50 | * [source,java] 51 | * -- 52 | * /** 53 | * * = Asciidoclet 54 | * * 55 | * * A Javadoc Doclet that uses https://asciidoctor.org[Asciidoctor] 56 | * * to render https://asciidoc.org[AsciiDoc] markup in Javadoc comments. 57 | * * 58 | * * @author https://github.com/johncarl81[John Ericksen] 59 | * *\/ 60 | * public class Asciidoclet extends Doclet { 61 | * private final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); // <1> 62 | * 63 | * @SuppressWarnings("UnusedDeclaration") 64 | * public static boolean start(RootDoc rootDoc) { 65 | * new Asciidoclet().render(rootDoc); // <2> 66 | * return Standard.start(rootDoc); 67 | * } 68 | * } 69 | * -- 70 | * <1> Creates an instance of the Asciidoctor Java integration 71 | * <2> Runs Javadoc comment strings through Asciidoctor 72 | * 73 | * Inline code:: `code()` or +code()+ 74 | * 75 | * Headings:: 76 | * + 77 | * -- 78 | * [float] 79 | * = Heading 1 80 | * 81 | * [float] 82 | * == Heading 2 83 | * 84 | * [float] 85 | * === Heading 3 86 | * 87 | * [float] 88 | * ==== Heading 4 89 | * 90 | * [float] 91 | * ===== Heading 5 92 | * -- 93 | * 94 | * Links:: 95 | * Doc Writer + 96 | * https://asciidoc.org[AsciiDoc] is a lightweight markup language. + 97 | * Learn more about it at https://asciidoctor.org. + 98 | * 99 | * Bullets:: 100 | * + 101 | * -- 102 | * .Unnumbered 103 | * * bullet 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 | * -- 121 | * + 122 | * -- 123 | * .Numbered 124 | * . bullet 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 | * -- 140 | * 141 | * Tables:: 142 | * + 143 | * .An example table 144 | * [cols="3", options="header"] 145 | * |=== 146 | * |Column 1 147 | * |Column 2 148 | * |Column 3 149 | * 150 | * |1 151 | * |Item 1 152 | * |a 153 | * 154 | * |2 155 | * |Item 2 156 | * |b 157 | * 158 | * |3 159 | * |Item 3 160 | * |c 161 | * |=== 162 | * 163 | * Sidebar block:: 164 | * + 165 | * .Optional Title 166 | * **** 167 | * Usage: Notes in a sidebar, naturally. 168 | * **** 169 | * 170 | * Admonitions:: 171 | * + 172 | * IMPORTANT: Check this out! 173 | * 174 | * @author https://github.com/johncarl81[John Ericksen] 175 | * @version 0.1.0 176 | * @see org.asciidoctor.asciidoclet.Asciidoclet 177 | * @since 0.1.0 178 | * @serial (or @serialField or @serialData) 179 | */ 180 | package org.asciidoctor.asciidoclet; 181 | -------------------------------------------------------------------------------- /src/main/java/overview.adoc: -------------------------------------------------------------------------------- 1 | = Asciidoclet 2 | 3 | include::../../../docs/modules/ROOT/pages/usage.adoc[leveloffset=+1,tags=!warning-message] 4 | 5 | include::../../../docs/modules/ROOT/pages/options.adoc[leveloffset=+1] 6 | 7 | @see https://github.com/asciidoctor/asciidoclet[Asciidoclet on Github^] 8 | @see https://asciidoctor.org/docs[Asciidoctor Documentation^] 9 | -------------------------------------------------------------------------------- /src/main/resources/coderay-asciidoctor.css: -------------------------------------------------------------------------------- 1 | /* Stylesheet for CodeRay to match GitHub theme | MIT License | https://foundation.zurb.com */ 2 | /*pre.CodeRay {background-color:#f7f7f8;}*/ 3 | .CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em} 4 | .CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)} 5 | .CodeRay .line-numbers strong{font-weight: normal} 6 | table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none} 7 | table.CodeRay td{vertical-align: top} 8 | table.CodeRay td.line-numbers{text-align:right} 9 | table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)} 10 | table.CodeRay td.code{padding:0 0 0 .5em} 11 | table.CodeRay td.code>pre{padding:0} 12 | .CodeRay .debug{color:#fff !important;background:#000080 !important} 13 | .CodeRay .annotation{color:#007} 14 | .CodeRay .attribute-name{color:#000080} 15 | .CodeRay .attribute-value{color:#700} 16 | .CodeRay .binary{color:#509} 17 | .CodeRay .comment{color:#998;font-style:italic} 18 | .CodeRay .char{color:#04d} 19 | .CodeRay .char .content{color:#04d} 20 | .CodeRay .char .delimiter{color:#039} 21 | .CodeRay .class{color:#458;font-weight:bold} 22 | .CodeRay .complex{color:#a08} 23 | .CodeRay .constant,.CodeRay .predefined-constant{color:#008080} 24 | .CodeRay .color{color:#099} 25 | .CodeRay .class-variable{color:#369} 26 | .CodeRay .decorator{color:#b0b} 27 | .CodeRay .definition{color:#099} 28 | .CodeRay .delimiter{color:#000} 29 | .CodeRay .doc{color:#970} 30 | .CodeRay .doctype{color:#34b} 31 | .CodeRay .doc-string{color:#d42} 32 | .CodeRay .escape{color:#666} 33 | .CodeRay .entity{color:#800} 34 | .CodeRay .error{color:#808} 35 | .CodeRay .exception{color:inherit} 36 | .CodeRay .filename{color:#099} 37 | .CodeRay .function{color:#900;font-weight:bold} 38 | .CodeRay .global-variable{color:#008080} 39 | .CodeRay .hex{color:#058} 40 | .CodeRay .integer,.CodeRay .float{color:#099} 41 | .CodeRay .include{color:#555} 42 | .CodeRay .inline{color:#00} 43 | .CodeRay .inline .inline{background:#ccc} 44 | .CodeRay .inline .inline .inline{background:#bbb} 45 | .CodeRay .inline .inline-delimiter{color:#d14} 46 | .CodeRay .inline-delimiter{color:#d14} 47 | .CodeRay .important{color:#555;font-weight:bold} 48 | .CodeRay .interpreted{color:#b2b} 49 | .CodeRay .instance-variable{color:#008080} 50 | .CodeRay .label{color:#970} 51 | .CodeRay .local-variable{color:#963} 52 | .CodeRay .octal{color:#40e} 53 | .CodeRay .predefined{color:#369} 54 | .CodeRay .preprocessor{color:#579} 55 | .CodeRay .pseudo-class{color:#555} 56 | .CodeRay .directive{font-weight:bold} 57 | .CodeRay .type{font-weight:bold} 58 | .CodeRay .predefined-type{color:inherit} 59 | .CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold} 60 | .CodeRay .key{color:#808} 61 | .CodeRay .key .delimiter{color:#606} 62 | .CodeRay .key .char{color:#80f} 63 | .CodeRay .value{color:#088} 64 | .CodeRay .regexp .delimiter{color:#808} 65 | .CodeRay .regexp .content{color:#808} 66 | .CodeRay .regexp .modifier{color:#808} 67 | .CodeRay .regexp .char{color:#d14} 68 | .CodeRay .regexp .function{color:#404;font-weight:bold} 69 | .CodeRay .string{color:#d20} 70 | .CodeRay .string .string .string{background:#ffd0d0} 71 | .CodeRay .string .content{color:#d14} 72 | .CodeRay .string .char{color:#d14} 73 | .CodeRay .string .delimiter{color:#d14} 74 | .CodeRay .shell{color:#d14} 75 | .CodeRay .shell .delimiter{color:#d14} 76 | .CodeRay .symbol{color:#990073} 77 | .CodeRay .symbol .content{color:#a60} 78 | .CodeRay .symbol .delimiter{color:#630} 79 | .CodeRay .tag{color:#008080} 80 | .CodeRay .tag-special{color:#d70} 81 | .CodeRay .variable{color:#036} 82 | .CodeRay .insert{background:#afa} 83 | .CodeRay .delete{background:#faa} 84 | .CodeRay .change{color:#aaf;background:#007} 85 | .CodeRay .head{color:#f8f;background:#505} 86 | .CodeRay .insert .insert{color:#080} 87 | .CodeRay .delete .delete{color:#800} 88 | .CodeRay .change .change{color:#66f} 89 | .CodeRay .head .head{color:#f4f} 90 | -------------------------------------------------------------------------------- /src/main/resources/templates/paragraph.html.haml: -------------------------------------------------------------------------------- 1 | %p{:id=>@id, :class=>(attr 'role')}<= content 2 | -------------------------------------------------------------------------------- /src/main/resources/templates/section.html.haml: -------------------------------------------------------------------------------- 1 | -# Simplified section code from lib/asciidoctor/converter/html5.rb 2 | - @htag = %(h#{level + 1}) 3 | - haml_tag @htag, title, :id => id 4 | - if level == 1 5 | .sectionbody 6 | = content 7 | - else 8 | = content 9 | -------------------------------------------------------------------------------- /src/test/java/org/asciidoctor/asciidoclet/AsciidocletIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import java.io.IOException; 19 | import java.lang.reflect.Method; 20 | import java.nio.file.FileVisitResult; 21 | import java.nio.file.Files; 22 | import java.nio.file.Path; 23 | import java.nio.file.Paths; 24 | import java.nio.file.SimpleFileVisitor; 25 | import java.nio.file.attribute.BasicFileAttributes; 26 | import java.util.Arrays; 27 | import java.util.stream.Collectors; 28 | 29 | import static org.assertj.core.api.Assertions.assertThat; 30 | 31 | public class AsciidocletIntegrationTest { 32 | 33 | /** 34 | * Running this test needs the following JVM argument: 35 | * --add-exports jdk.javadoc/jdk.javadoc.internal.tool=asciidoclet 36 | */ 37 | //@Test 38 | void testJavadocIntegration() throws Exception { 39 | Method execute = Class.forName("jdk.javadoc.internal.tool.Main").getMethod("execute", String[].class); 40 | execute.setAccessible(true); 41 | String outputDirectory = "target/javadoc-output"; 42 | deleteRecursively(outputDirectory); 43 | int result = (int) execute.invoke(null, (Object) new String[]{ 44 | "--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=asciidoclet", 45 | "--add-exports=jdk.compiler/com.sun.tools.javac.parser=asciidoclet", 46 | "--add-exports=jdk.compiler/com.sun.tools.javac.tree=asciidoclet", 47 | "--add-exports=jdk.compiler/com.sun.tools.javac.model=asciidoclet", 48 | "--module-path", classpath(), 49 | "-doclet", "org.asciidoctor.asciidoclet.Asciidoclet", 50 | "--source-path", "src/main/java", 51 | "-d", outputDirectory, 52 | "-Xdoclint:all,-html,-accessibility", // TODO We should ideally generate valid HTML5. 53 | "-overview", "src/main/java/overview.adoc", 54 | "--base-dir", ".", 55 | "org.asciidoctor.asciidoclet", 56 | }); 57 | assertThat(result).isEqualTo(0); 58 | } 59 | 60 | private void deleteRecursively(String outputDirectory) throws IOException { 61 | Path outputPath = Paths.get(outputDirectory); 62 | if (Files.exists(outputPath)) { 63 | Files.walkFileTree(outputPath, new SimpleFileVisitor<>() { 64 | @Override 65 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 66 | Files.deleteIfExists(file); 67 | return FileVisitResult.CONTINUE; 68 | } 69 | 70 | @Override 71 | public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { 72 | Files.deleteIfExists(dir); 73 | return FileVisitResult.CONTINUE; 74 | } 75 | }); 76 | } 77 | } 78 | 79 | private String classpath() { 80 | return Arrays.stream(System.getProperty("java.class.path").split(":")) 81 | .filter(s -> !s.contains("ideaIU")) // Filter out Intellij jar files. 82 | .collect(Collectors.joining(":")); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/org/asciidoctor/asciidoclet/AsciidoctorConverterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import org.junit.jupiter.api.BeforeEach; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.asciidoctor.asciidoclet.AsciidoctorConverter.MARKER; 22 | import static org.assertj.core.api.Assertions.assertThat; 23 | 24 | /** 25 | * @author John Ericksen 26 | */ 27 | class AsciidoctorConverterTest { 28 | 29 | private static final String LINEBREAK = "\r?\n"; 30 | 31 | private AsciidoctorConverter converter; 32 | private StubReporter reporter = new StubReporter(); 33 | 34 | @BeforeEach 35 | void setup() { 36 | DocletOptions options = new DocletOptions(reporter); 37 | converter = new AsciidoctorConverter(options, reporter); 38 | } 39 | 40 | @Test 41 | void testAtLiteralRender() { 42 | String actual = converter.convert("{@literal @}Test"); 43 | assertThat(actual).matches(MARKER + "

\\{@literal @}Test

" + LINEBREAK); 44 | } 45 | 46 | @Test 47 | void testTagRender() { 48 | String actual = converter.convert("input\n@tagName tagText"); 49 | assertThat(actual).matches(MARKER + "

input

" + LINEBREAK + "@tagName tagText" + LINEBREAK); 50 | } 51 | 52 | @Test 53 | void testCleanInput() { 54 | assertThat(AsciidoctorConverter.cleanJavadocInput(" test1\n test2\n")).isEqualTo("test1\ntest2"); 55 | assertThat(AsciidoctorConverter.cleanJavadocInput("/*\ntest\n*\\/")).isEqualTo("/*\ntest\n*/"); 56 | assertThat(AsciidoctorConverter.cleanJavadocInput("{at}")).isEqualTo("@"); 57 | assertThat(AsciidoctorConverter.cleanJavadocInput("{slash}")).isEqualTo("/"); 58 | } 59 | 60 | @Test 61 | void testComment() { 62 | assertThat(converter.convert("comment\n")) 63 | .matches(MARKER + "

comment

" + LINEBREAK); 64 | } 65 | 66 | @Test 67 | void testParameterWithoutTypeTag() { 68 | assertThat(converter.convert("comment\n@param p description")) 69 | .matches(MARKER + "

comment

" + LINEBREAK + "@param p description" + LINEBREAK); 70 | assertThat(converter.convert("comment\n@param p")) 71 | .matches(MARKER + "

comment

" + LINEBREAK + "@param p" + LINEBREAK); 72 | assertThat(converter.convert("comment\n@param")) 73 | .matches(MARKER + "

comment

" + LINEBREAK + "@param " + LINEBREAK); 74 | } 75 | 76 | @Test 77 | void testParamTagWithTypeParameter() { 78 | String commentText = "comment"; 79 | String param1Name = "T"; 80 | String param1Text = "<" + param1Name + ">"; 81 | String param2Name = "X"; 82 | String param2Desc = "description"; 83 | String param2Text = "<" + param2Name + "> " + param2Desc; 84 | String sourceText = commentText + "\n@param " + param1Text + "\n@param " + param2Text; 85 | 86 | assertThat(converter.convert(sourceText)) 87 | .matches(MARKER + "

comment

" + LINEBREAK + "@param " + LINEBREAK + "@param description" + LINEBREAK); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/org/asciidoctor/asciidoclet/AsciidoctorOptionsFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import org.asciidoctor.Asciidoctor; 19 | import org.asciidoctor.Options; 20 | import org.asciidoctor.SafeMode; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | import org.mockito.Mockito; 24 | 25 | import java.io.File; 26 | import java.util.List; 27 | import java.util.Map; 28 | import java.util.Optional; 29 | 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | 32 | class AsciidoctorOptionsFactoryTest { 33 | 34 | private Asciidoctor asciidoctor = Asciidoctor.Factory.create(); 35 | private StubReporter reporter = new StubReporter(); 36 | 37 | private AsciidoctorOptionsFactory optionsFactory; 38 | 39 | @BeforeEach 40 | void setup() { 41 | optionsFactory = new AsciidoctorOptionsFactory(asciidoctor, reporter); 42 | } 43 | 44 | @Test 45 | void createsDefaultOptions() { 46 | DocletOptions docletOptions = new DocletOptions(reporter); 47 | 48 | Options options = optionsFactory.create(docletOptions, null); 49 | 50 | Map optionsMap = options.map(); 51 | assertContainsDefaultOptions(optionsMap, 3); 52 | 53 | Map attributes = (Map) optionsMap.get("attributes"); 54 | assertContainsDefaultAttributes(attributes, 11); 55 | } 56 | 57 | @Test 58 | void withCustomAttributes() { 59 | DocletOptions docletOptions = Mockito.mock(DocletOptions.class); 60 | Mockito.when(docletOptions.attributes()).thenReturn(List.of("my-attribute=my-value", "another=42")); 61 | 62 | Options options = optionsFactory.create(docletOptions, null); 63 | 64 | Map optionsMap = options.map(); 65 | assertContainsDefaultOptions(optionsMap, 3); 66 | assertThat(optionsMap).hasSize(3); 67 | 68 | Map attributes = (Map) optionsMap.get("attributes"); 69 | assertContainsDefaultAttributes(attributes, 13); 70 | assertThat(attributes) 71 | .containsEntry("my-attribute", "my-value") 72 | .containsEntry("another", "42"); 73 | } 74 | 75 | @Test 76 | void withCustomBaseDir() { 77 | DocletOptions docletOptions = Mockito.mock(DocletOptions.class); 78 | File baseDir = new File("some/path"); 79 | Mockito.when(docletOptions.baseDir()).thenReturn(Optional.of(baseDir)); 80 | 81 | Options options = optionsFactory.create(docletOptions, null); 82 | 83 | Map optionsMap = options.map(); 84 | assertContainsDefaultOptions(optionsMap, 4); 85 | assertThat(optionsMap) 86 | .containsEntry("base_dir", baseDir.getAbsolutePath()); 87 | 88 | Map attributes = (Map) optionsMap.get("attributes"); 89 | assertContainsDefaultAttributes(attributes, 11); 90 | } 91 | 92 | @Test 93 | void withTemplateDir() { 94 | DocletOptions docletOptions = new DocletOptions(reporter); 95 | OutputTemplates outputTemplates = OutputTemplates.create(reporter); 96 | assertThat(outputTemplates.templateDir()).isNotEmptyDirectory(); 97 | 98 | Options options = optionsFactory.create(docletOptions, outputTemplates); 99 | 100 | Map optionsMap = options.map(); 101 | assertContainsDefaultOptions(optionsMap, 4); 102 | assertThat(optionsMap) 103 | .containsEntry("template_dirs", List.of(outputTemplates.templateDir().toString())); 104 | 105 | Map attributes = (Map) optionsMap.get("attributes"); 106 | assertContainsDefaultAttributes(attributes, 11); 107 | } 108 | 109 | @Test 110 | void withRequires() { 111 | DocletOptions mock = Mockito.mock(DocletOptions.class); 112 | // Use gems available in the classpath to avoid errors 113 | Mockito.when(mock.requires()).thenReturn(List.of("asciidoctor", "coderay")); 114 | 115 | Options options = optionsFactory.create(mock, null); 116 | 117 | Map optionsMap = options.map(); 118 | assertContainsDefaultOptions(optionsMap, 3); 119 | assertThat(optionsMap).hasSize(3); 120 | 121 | Map attributes = (Map) optionsMap.get("attributes"); 122 | assertContainsDefaultAttributes(attributes, 11); 123 | } 124 | 125 | private static void assertContainsDefaultOptions(Map options, int size) { 126 | assertThat(options) 127 | .containsEntry("backend", "html5") 128 | .containsEntry("safe", SafeMode.SAFE.getLevel()) 129 | .containsKey("attributes"); 130 | assertThat(options).hasSize(size); 131 | } 132 | 133 | private static void assertContainsDefaultAttributes(Map attributes, int size) { 134 | assertThat(attributes) 135 | .containsEntry("at", "@") 136 | .containsEntry("slash", "/") 137 | .containsEntry("icons", null) 138 | .containsEntry("idprefix", "") 139 | .containsEntry("idseparator", "-") 140 | .containsEntry("javadoc", "") 141 | .containsEntry("showtitle", true) 142 | .containsEntry("source-highlighter", "coderay") 143 | .containsEntry("coderay-css", "class") 144 | .containsEntry("env-asciidoclet", "") 145 | .containsEntry("env", "asciidoclet"); 146 | assertThat(attributes).hasSize(size); 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/test/java/org/asciidoctor/asciidoclet/AttributesLoaderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import org.asciidoctor.Asciidoctor; 19 | import org.junit.jupiter.api.BeforeEach; 20 | import org.junit.jupiter.api.Test; 21 | import org.junit.jupiter.api.io.TempDir; 22 | 23 | import java.io.IOException; 24 | import java.nio.charset.StandardCharsets; 25 | import java.nio.file.Files; 26 | import java.nio.file.Path; 27 | import java.nio.file.StandardOpenOption; 28 | import java.util.HashMap; 29 | import java.util.List; 30 | import java.util.Map; 31 | 32 | import static org.assertj.core.api.Assertions.assertThat; 33 | 34 | class AttributesLoaderTest { 35 | 36 | private final Asciidoctor asciidoctor = Asciidoctor.Factory.create(); 37 | private final StubReporter reporter = new StubReporter(); 38 | 39 | private Path tmpDir; 40 | 41 | @BeforeEach 42 | void before(@TempDir Path tmpDir) { 43 | this.tmpDir = tmpDir; 44 | } 45 | 46 | @Test 47 | void testNoAttributes() { 48 | DocletOptions options = new DocletOptions(reporter); 49 | AttributesLoader loader = new AttributesLoader(asciidoctor, options, reporter); 50 | 51 | Map attrs = loader.load(); 52 | 53 | assertThat(attrs).isEmpty(); 54 | reporter.assertNoMoreInteractions(); 55 | } 56 | 57 | @Test 58 | void testOnlyCommandLineAttributes() { 59 | DocletOptions options = new DocletOptions(reporter); 60 | options.collect(AsciidocletOptions.ATTRIBUTE, List.of("foo=bar, foo2=foo-two, not!, override=override@")); 61 | AttributesLoader loader = new AttributesLoader(asciidoctor, options, reporter); 62 | 63 | Map attrs = loader.load(); 64 | 65 | assertThat(attrs) 66 | .containsEntry("foo", "bar") 67 | .containsEntry("foo2", "foo-two") 68 | .containsEntry("override", "override@") 69 | .containsKey("not!"); 70 | assertThat(attrs) 71 | .doesNotContainKey("not"); 72 | reporter.assertNoMoreInteractions(); 73 | } 74 | 75 | @Test 76 | void testOnlyCommandLineAttributesMulti() { 77 | DocletOptions options = new DocletOptions(reporter); 78 | options.collect(AsciidocletOptions.ATTRIBUTE, List.of( 79 | "foo=bar", "foo2=foo two", "not!", "override=override@")); 80 | AttributesLoader loader = new AttributesLoader(asciidoctor, options, reporter); 81 | 82 | Map attrs = loader.load(); 83 | 84 | assertThat(attrs) 85 | .containsEntry("foo", "bar") 86 | .containsEntry("foo2", "foo two") 87 | .containsEntry("override", "override@") 88 | .containsKey("not!"); 89 | assertThat(attrs) 90 | .doesNotContainKey("not"); 91 | reporter.assertNoMoreInteractions(); 92 | } 93 | 94 | @Test 95 | void testOnlyAttributesFile() throws IOException { 96 | Path attrsFile = createTempFile("attrs.adoc", ATTRS); 97 | 98 | DocletOptions options = new DocletOptions(reporter); 99 | options.collect(AsciidocletOptions.ATTRIBUTES_FILE, List.of(attrsFile.toAbsolutePath().toString())); 100 | AttributesLoader loader = new AttributesLoader(asciidoctor, options, reporter); 101 | 102 | Map attrs = loader.load(); 103 | 104 | assertThat(attrs) 105 | .containsEntry("foo", "BAR") 106 | .containsEntry("foo2", "BAR-TWO") 107 | .containsEntry("override", "OVERRIDE") 108 | .containsKey("not"); 109 | reporter.assertNoMoreInteractions(); 110 | } 111 | 112 | @Test 113 | void testCommandLineAndAttributesFile() throws IOException { 114 | Path attrsFile = createTempFile("attrs.adoc", ATTRS); 115 | 116 | DocletOptions options = new DocletOptions(reporter); 117 | options.collect(AsciidocletOptions.ATTRIBUTE, List.of("foo=bar, not!, override=override@")); 118 | options.collect(AsciidocletOptions.ATTRIBUTES_FILE, List.of(attrsFile.toAbsolutePath().toString())); 119 | AttributesLoader loader = new AttributesLoader(asciidoctor, options, reporter); 120 | 121 | Map attrs = new HashMap<>(loader.load()); 122 | 123 | assertThat(attrs) 124 | .containsEntry("foo", "bar") 125 | .containsEntry("foo2", "bar-TWO") 126 | .containsEntry("override", "OVERRIDE") 127 | .containsKey("not!"); 128 | assertThat(attrs) 129 | .doesNotContainKey("not"); 130 | reporter.assertNoMoreInteractions(); 131 | } 132 | 133 | @Test 134 | void testAttributesFileIncludeFromBaseDir() throws IOException { 135 | Path attrsFile = createTempFile("attrs.adoc", "include::attrs-include.adoc[]"); 136 | createTempFile("attrs-include.adoc", ATTRS); 137 | 138 | DocletOptions options = new DocletOptions(reporter); 139 | options.collect(AsciidocletOptions.ATTRIBUTES_FILE, List.of(attrsFile.toAbsolutePath().toString())); 140 | options.collect(AsciidocletOptions.BASEDIR, List.of(attrsFile.getParent().toAbsolutePath().toString())); 141 | AttributesLoader loader = new AttributesLoader(asciidoctor, options, reporter); 142 | 143 | Map attrs = loader.load(); 144 | 145 | assertThat(attrs) 146 | .containsEntry("foo", "BAR") 147 | .containsEntry("foo2", "BAR-TWO") 148 | .containsEntry("override", "OVERRIDE") 149 | .containsKey("not"); 150 | 151 | reporter.assertNoMoreInteractions(); 152 | } 153 | 154 | @Test 155 | void testAttributesFileIncludeFromOtherDir() throws IOException { 156 | Path attrsFile = createTempFile("attrs.adoc", "include::{includedir}/attrs-include.adoc[]"); 157 | createTempFile("foo", "attrs-include.adoc", ATTRS); 158 | 159 | DocletOptions options = new DocletOptions(reporter); 160 | options.collect(AsciidocletOptions.ATTRIBUTES_FILE, List.of(attrsFile.toAbsolutePath().toString())); 161 | options.collect(AsciidocletOptions.BASEDIR, List.of(attrsFile.getParent().toAbsolutePath().toString())); 162 | options.collect(AsciidocletOptions.ATTRIBUTE, List.of("includedir=foo")); 163 | AttributesLoader loader = new AttributesLoader(asciidoctor, options, reporter); 164 | 165 | Map attrs = loader.load(); 166 | 167 | assertThat(attrs) 168 | .containsEntry("foo", "BAR") 169 | .containsEntry("foo2", "BAR-TWO") 170 | .containsEntry("override", "OVERRIDE") 171 | .containsKey("not"); 172 | 173 | reporter.assertNoMoreInteractions(); 174 | } 175 | 176 | private Path createTempFile(String name, String content) throws IOException { 177 | return writeFile(content, tmpDir.resolve(name)); 178 | } 179 | 180 | private Path createTempFile(String dir, String name, String content) throws IOException { 181 | Path directory = tmpDir.resolve(dir); 182 | Files.createDirectories(directory); 183 | return writeFile(content, directory.resolve(name)); 184 | } 185 | 186 | private Path writeFile(String content, Path file) throws IOException { 187 | byte[] bytes = content.getBytes(StandardCharsets.UTF_8); 188 | Files.write(file, bytes, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); 189 | return file; 190 | } 191 | 192 | static final String ATTRS = 193 | ":foo: BAR\n" + 194 | ":foo2: {foo}-TWO\n" + 195 | ":not: FOO\n" + 196 | ":override: OVERRIDE\n"; 197 | } 198 | -------------------------------------------------------------------------------- /src/test/java/org/asciidoctor/asciidoclet/DocletOptionsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import jdk.javadoc.doclet.Reporter; 19 | import org.junit.jupiter.api.BeforeEach; 20 | import org.junit.jupiter.api.Test; 21 | import org.junit.jupiter.params.ParameterizedTest; 22 | import org.junit.jupiter.params.provider.Arguments; 23 | import org.junit.jupiter.params.provider.MethodSource; 24 | 25 | import java.nio.charset.Charset; 26 | import java.nio.charset.StandardCharsets; 27 | import java.util.List; 28 | import java.util.stream.Stream; 29 | 30 | import static org.assertj.core.api.Assertions.assertThat; 31 | 32 | class DocletOptionsTest { 33 | 34 | private Reporter reporter; 35 | 36 | @BeforeEach 37 | void setUp() { 38 | reporter = new StubReporter(); 39 | } 40 | 41 | @Test 42 | void testGetBaseDir() { 43 | assertThat(new DocletOptions(reporter).baseDir()).isNotPresent(); 44 | 45 | DocletOptions options = new DocletOptions(reporter); 46 | options.collect(AsciidocletOptions.BASEDIR, List.of("test")); 47 | options.validate(); 48 | 49 | assertThat(options.baseDir().get().getName()).isEqualTo("test"); 50 | } 51 | 52 | @Test 53 | void testAttributes() { 54 | final String attribute = "attribute-key=attribute-value"; 55 | assertThat(new DocletOptions(reporter).baseDir()).isNotPresent(); 56 | 57 | DocletOptions options = new DocletOptions(reporter); 58 | options.collect(AsciidocletOptions.ATTRIBUTE, List.of(attribute)); 59 | options.validate(); 60 | 61 | assertThat(options.attributes()).hasSize(1); 62 | assertThat(options.attributes()).first().isEqualTo(attribute); 63 | } 64 | 65 | @Test 66 | void testAttributesLong() { 67 | final String attribute = "attribute-key=attribute-value"; 68 | assertThat(new DocletOptions(reporter).baseDir()).isNotPresent(); 69 | 70 | DocletOptions options = new DocletOptions(reporter); 71 | options.collect(AsciidocletOptions.ATTRIBUTE_LONG, List.of(attribute)); 72 | options.validate(); 73 | 74 | assertThat(options.attributes()).hasSize(1); 75 | assertThat(options.attributes()).first().isEqualTo(attribute); 76 | } 77 | 78 | @Test 79 | void testDefaultEncoding() { 80 | DocletOptions options = new DocletOptions(reporter); 81 | 82 | assertThat(options.encoding()).isEqualTo(Charset.defaultCharset()); 83 | } 84 | 85 | @ParameterizedTest 86 | @MethodSource("encodingsProvider") 87 | void testEncoding(String encoding, Charset expected) { 88 | DocletOptions options = new DocletOptions(reporter); 89 | options.collect(AsciidocletOptions.ENCODING, List.of(encoding)); 90 | options.validate(); 91 | assertThat(options.encoding()).isEqualTo(expected); 92 | } 93 | 94 | private static Stream encodingsProvider() { 95 | return Stream.of( 96 | Arguments.of("UTF-8", StandardCharsets.UTF_8), 97 | Arguments.of("US-ASCII", StandardCharsets.US_ASCII), 98 | Arguments.of("ISO-8859-1", StandardCharsets.ISO_8859_1) 99 | ); 100 | } 101 | 102 | @Test 103 | void testStylesheetFile() { 104 | assertThat(new DocletOptions(reporter).stylesheet()).isNotPresent(); 105 | 106 | DocletOptions options = new DocletOptions(reporter); 107 | options.collect(AsciidocletOptions.STYLESHEET, List.of("foo.css")); 108 | options.validate(); 109 | assertThat(options.stylesheet().get().getName()).isEqualTo("foo.css"); 110 | } 111 | 112 | @Test 113 | void testRequires() { 114 | assertThat(new DocletOptions(reporter).requires()).isEmpty(); 115 | 116 | DocletOptions options = new DocletOptions(reporter); 117 | options.collect(AsciidocletOptions.REQUIRE, List.of("foo", "bar")); 118 | options.validate(); 119 | assertThat(options.requires()).containsExactlyInAnyOrder("foo", "bar"); 120 | 121 | options = new DocletOptions(reporter); 122 | options.collect(AsciidocletOptions.REQUIRE, List.of("a", "diagrams/awesome")); 123 | options.collect(AsciidocletOptions.REQUIRE_LONG, List.of("bar")); 124 | options.collect(AsciidocletOptions.REQUIRE_LONG, List.of("baz,noddy")); 125 | options.validate(); 126 | assertThat(options.requires()).containsExactlyInAnyOrder("a", "diagrams/awesome", "bar", "baz", "noddy"); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/test/java/org/asciidoctor/asciidoclet/JavadocParserTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import org.asciidoctor.asciidoclet.JavadocParser.Tag; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.assertj.core.api.Assertions.assertThat; 22 | 23 | class JavadocParserTest { 24 | 25 | @Test 26 | void parsePlainBody() { 27 | JavadocParser parser = JavadocParser.parse("plain body"); 28 | assertThat(parser.getCommentBody()).isEqualTo("plain body"); 29 | } 30 | 31 | @Test 32 | void parsePlainBodyAndTag() { 33 | JavadocParser parser = JavadocParser.parse("plain body\n@see OtherPlace"); 34 | assertThat(parser.getCommentBody()).isEqualTo("plain body"); 35 | assertThat(parser.tags()) 36 | .usingRecursiveFieldByFieldElementComparator() 37 | .contains(new Tag("@see", "OtherPlace")); 38 | } 39 | 40 | @Test 41 | void parseTag() { 42 | JavadocParser parser = JavadocParser.parse("@see Other"); 43 | assertThat(parser.getCommentBody()).isEqualTo(""); 44 | assertThat(parser.tags()) 45 | .usingRecursiveFieldByFieldElementComparator() 46 | .contains(new Tag("@see", "Other")); 47 | } 48 | 49 | @Test 50 | void parseTagWithNewLine() { 51 | JavadocParser parser = JavadocParser.parse("@see Other\n place"); 52 | assertThat(parser.getCommentBody()).isEqualTo(""); 53 | assertThat(parser.tags()) 54 | .usingRecursiveFieldByFieldElementComparator() 55 | .contains(new Tag("@see", "Other\n place")); 56 | } 57 | 58 | @Test 59 | void parseMultipleTags() { 60 | JavadocParser parser = JavadocParser.parse("@see Other\n@throws Exception"); 61 | assertThat(parser.getCommentBody()).isEqualTo(""); 62 | assertThat(parser.tags()) 63 | .usingRecursiveFieldByFieldElementComparator() 64 | .containsExactlyInAnyOrder(new Tag("@see", "Other"), new Tag("@throws", "Exception")); 65 | } 66 | 67 | @Test 68 | void parseMultipleMultiLineTags() { 69 | JavadocParser parser = JavadocParser.parse("@see Other\n place\nnearby\n@throws Exception\non error"); 70 | assertThat(parser.getCommentBody()).isEqualTo(""); 71 | assertThat(parser.tags()) 72 | .usingRecursiveFieldByFieldElementComparator() 73 | .containsExactlyInAnyOrder(new Tag("@see", "Other\n place\nnearby"), new Tag("@throws", "Exception\non error")); 74 | } 75 | 76 | @Test 77 | void parseWithBlockInBody() { 78 | JavadocParser parser = JavadocParser.parse("Body\n--\n@see bla\n--\n@see foo"); 79 | assertThat(parser.getCommentBody()).isEqualTo("Body\n--\n@see bla\n--"); 80 | assertThat(parser.tags()) 81 | .usingRecursiveFieldByFieldElementComparator() 82 | .contains(new Tag("@see", "foo")); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/org/asciidoctor/asciidoclet/LazyDocCommentTableProcessorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import com.sun.tools.javac.parser.LazyDocCommentTable; 19 | import com.sun.tools.javac.parser.ParserFactory; 20 | import com.sun.tools.javac.parser.Tokens.Comment; 21 | import com.sun.tools.javac.util.Context; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import javax.tools.FileObject; 25 | import javax.tools.JavaFileManager; 26 | import javax.tools.JavaFileObject; 27 | import java.io.IOException; 28 | import java.lang.reflect.Constructor; 29 | import java.lang.reflect.InvocationTargetException; 30 | import java.util.Iterator; 31 | import java.util.Set; 32 | import java.util.function.Function; 33 | 34 | class LazyDocCommentTableProcessorTest { 35 | 36 | @Test 37 | void testProcessComments() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { 38 | // Just make sure the processComments method returns normally for now. 39 | LazyDocCommentTableProcessor.processComments(createLazyDocCommentTable(), commentMapper()); 40 | } 41 | 42 | private LazyDocCommentTable createLazyDocCommentTable() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { 43 | Constructor constructor = LazyDocCommentTable.class.getDeclaredConstructor(ParserFactory.class); 44 | constructor.setAccessible(true); 45 | 46 | return constructor.newInstance(createParserFactory()); 47 | } 48 | 49 | private Function commentMapper() { 50 | return Function.identity(); 51 | } 52 | 53 | private ParserFactory createParserFactory() { 54 | return ParserFactory.instance(createContext()); 55 | } 56 | 57 | private static Context createContext() { 58 | Context context = new Context(); 59 | context.put(JavaFileManager.class, createJavaFileManager()); 60 | return context; 61 | } 62 | 63 | private static JavaFileManager createJavaFileManager() { 64 | return new JavaFileManager() { 65 | @Override 66 | public ClassLoader getClassLoader(Location location) { 67 | return null; 68 | } 69 | 70 | @Override 71 | public Iterable list(Location location, String packageName, Set kinds, boolean recurse) throws IOException { 72 | return null; 73 | } 74 | 75 | @Override 76 | public String inferBinaryName(Location location, JavaFileObject file) { 77 | return null; 78 | } 79 | 80 | @Override 81 | public boolean isSameFile(FileObject a, FileObject b) { 82 | return false; 83 | } 84 | 85 | @Override 86 | public boolean handleOption(String current, Iterator remaining) { 87 | return false; 88 | } 89 | 90 | @Override 91 | public boolean hasLocation(Location location) { 92 | return false; 93 | } 94 | 95 | @Override 96 | public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException { 97 | return null; 98 | } 99 | 100 | @Override 101 | public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { 102 | return null; 103 | } 104 | 105 | @Override 106 | public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { 107 | return null; 108 | } 109 | 110 | @Override 111 | public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { 112 | return null; 113 | } 114 | 115 | @Override 116 | public void flush() { 117 | 118 | } 119 | 120 | @Override 121 | public void close() { 122 | 123 | } 124 | 125 | @Override 126 | public int isSupportedOption(String option) { 127 | return 0; 128 | } 129 | }; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/test/java/org/asciidoctor/asciidoclet/StubReporter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import com.sun.source.util.DocTreePath; 19 | import jdk.javadoc.doclet.Reporter; 20 | import org.assertj.core.api.Assertions; 21 | 22 | import javax.lang.model.element.Element; 23 | import javax.tools.Diagnostic; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.stream.Collectors; 27 | 28 | class StubReporter implements Reporter { 29 | 30 | private List> calls = new ArrayList<>(); 31 | 32 | @Override 33 | public void print(Diagnostic.Kind kind, String msg) { 34 | calls.add(List.of(kind, msg)); 35 | } 36 | 37 | @Override 38 | public void print(Diagnostic.Kind kind, DocTreePath path, String msg) { 39 | calls.add(List.of(kind, path, msg)); 40 | } 41 | 42 | @Override 43 | public void print(Diagnostic.Kind kind, Element e, String msg) { 44 | calls.add(List.of(kind, e, msg)); 45 | } 46 | 47 | void assertNoMoreInteractions() { 48 | if (!calls.isEmpty()) { 49 | String callsString = calls.stream().map(Object::toString).collect(Collectors.joining("\n\t", "\n\t", "")); 50 | Assertions.fail("Expected to not have any print calls, but got the following: " + callsString); 51 | } 52 | } 53 | 54 | List pullCall() { 55 | return calls.remove(0); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/org/asciidoctor/asciidoclet/StylesheetsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2024 John Ericksen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.asciidoctor.asciidoclet; 17 | 18 | import org.junit.jupiter.api.BeforeEach; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import javax.tools.Diagnostic; 22 | 23 | import static org.asciidoctor.asciidoclet.Stylesheets.JAVA11_STYLESHEET; 24 | import static org.asciidoctor.asciidoclet.Stylesheets.JAVA_STYLESHEET_FORMAT; 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | 27 | class StylesheetsTest { 28 | 29 | private Stylesheets stylesheets; 30 | private StubReporter reporter; 31 | 32 | @BeforeEach 33 | void setup() { 34 | reporter = new StubReporter(); 35 | stylesheets = new Stylesheets(reporter); 36 | } 37 | 38 | @Test 39 | void java11ShouldSelectStylesheet11() { 40 | assertThat(stylesheets.selectStylesheet("11")).isEqualTo(JAVA11_STYLESHEET); 41 | reporter.assertNoMoreInteractions(); 42 | } 43 | 44 | @Test 45 | void unknownNewJavaShouldSelectLatestStylesheet() { 46 | assertThat(stylesheets.selectStylesheet("42.3.0_12")).isEqualTo(String.format(JAVA_STYLESHEET_FORMAT, 17)); 47 | reporter.assertNoMoreInteractions(); 48 | } 49 | 50 | @Test 51 | void unknownOldJavaShouldSelectJava11StylesheetAndWarn() { 52 | assertThat(stylesheets.selectStylesheet("9.9.9")).isEqualTo(String.format(JAVA_STYLESHEET_FORMAT, 11)); 53 | assertThat(reporter.pullCall()).first().isEqualTo(Diagnostic.Kind.WARNING); 54 | reporter.assertNoMoreInteractions(); 55 | } 56 | 57 | @Test 58 | void java17ShouldSelectStylesheet17() { 59 | assertThat(stylesheets.selectStylesheet("17")).isEqualTo(String.format(JAVA_STYLESHEET_FORMAT, 17)); 60 | reporter.assertNoMoreInteractions(); 61 | } 62 | } 63 | --------------------------------------------------------------------------------