|
| 1 | += Contributing to Asciidoctor Spring Backends |
| 2 | + |
| 3 | +Unless otherwise noted, code in this project is released under the Apache 2.0 license. |
| 4 | +If you would like to contribute something, or want to hack on the code this document should help you get started. |
| 5 | + |
| 6 | + |
| 7 | +== Code of Conduct |
| 8 | +This project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct]. |
| 9 | +By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io. |
| 10 | + |
| 11 | + |
| 12 | + |
| 13 | +== Building from Source |
| 14 | +Source can be built from the command line using https://gradle.org[Gradle] on JDK 1.8 or above. |
| 15 | +We include https://docs.gradle.org/current/userguide/gradle_wrapper.html[Gradle's wrapper scripts] (`./gradlew` or `gradlew.bat`) that you can run rather than needing to install Gradle locally. |
| 16 | + |
| 17 | +The project can be built from the root directory using the standard Gradle command: |
| 18 | + |
| 19 | +[indent=0] |
| 20 | +---- |
| 21 | + $ ./gradlew build |
| 22 | +---- |
| 23 | + |
| 24 | + |
| 25 | + |
| 26 | +== Working with the Code |
| 27 | +There are quite a few moving parts to this project and a lot of different technologies involved. |
| 28 | +The project can broadly be split into two parts: |
| 29 | + |
| 30 | +. An AsciidoctorJ compatible extension providing the backends |
| 31 | +. A set of web assets (CSS & Javascript) used by the HTML generated by the backend. |
| 32 | + |
| 33 | + |
| 34 | + |
| 35 | +=== AsciidoctorJ Backend |
| 36 | +The AsciidoctorJ backend is Ruby and Java code that provides a https://www.rubydoc.info/gems/asciidoctor/Asciidoctor/Converter[Asciidoctor::Converter] implementation. |
| 37 | + |
| 38 | + |
| 39 | + |
| 40 | +==== Ruby Code |
| 41 | +The main converter implementation is written in Ruby. |
| 42 | +You can find the code in the link:src/main/ruby[`src/main/ruby`] folder. |
| 43 | + |
| 44 | +The code delegates to the standard `html5` converter, but changes a few areas to give us the HTML that we need. |
| 45 | +It also writes the CSS, Javascript and Images to the output directory. |
| 46 | + |
| 47 | +The code needs to be packaged as a Gem so that it can be picked up by AsciidoctorJ. |
| 48 | + |
| 49 | +This means that the Jar needs to have the following layout: |
| 50 | + |
| 51 | +---- |
| 52 | +specifications/ |
| 53 | + asciidoctor-spring-backends-0.0.0.gemspec |
| 54 | +gems/ |
| 55 | + asciidoctor-spring-backends-0.0.0/ |
| 56 | + lib/ |
| 57 | + asciidoctor-spring-backends |
| 58 | + data/ |
| 59 | +---- |
| 60 | + |
| 61 | +NOTE: The version number of the Gem isn't really important in our case so we set it to `0.0.0`. |
| 62 | + |
| 63 | +If you need to edit the `gemspec` file you can find it in link:src/main/ruby[`src/main/gemspec`]. |
| 64 | + |
| 65 | +AsciidoctorJ won't find the converter from the Gem alone, it needs to be told that it's a `requireLibrary`. |
| 66 | +This is done with the `SpringBackendsExtensionRegistry` class which is registered using `META-INF/services`. |
| 67 | + |
| 68 | + |
| 69 | + |
| 70 | +==== Java Code |
| 71 | +The code folding and chomping features are implemented in Java. |
| 72 | +You can find the code in link:src/main/java[src/main/java]. |
| 73 | + |
| 74 | +There's a `convert_listing_content` method in the Ruby code that uses JRuby features to call the `ListingContentConverters` class. |
| 75 | +The `ListingContentConverters` class is responsible for taking an Asciidoctor node and returning its content in a potentially modified form. |
| 76 | +There a bit of adapter logic needed to convert the `RubyObject`, but nothing too onerous. |
| 77 | + |
| 78 | +All the project tests are also written in Java. |
| 79 | +There's a mixture of both unit tests and integration tests. |
| 80 | +They're available at link:src/test/java[src/test/java]. |
| 81 | + |
| 82 | + |
| 83 | + |
| 84 | +==== Hacking on the Ruby Code |
| 85 | +If you want to iterate quickly on the Ruby code it's often easier to run it directly rather the using the Gradle build. |
| 86 | +You can do this by using the `asciidoctor` CLI command. |
| 87 | + |
| 88 | +[source,shell] |
| 89 | +---- |
| 90 | +$ asciidoctor --trace -r ./src/main/ruby/lib/asciidoctor-spring-backends.rb -b spring-html -D build/converted-asciidoc/ src/test/resources/standard.adoc |
| 91 | +---- |
| 92 | + |
| 93 | +NOTE: Using asciidoctor directly means that JRuby doesn't run. |
| 94 | +Java calls will not occur and `ListingContentConverters` features will not apply. |
| 95 | + |
| 96 | + |
| 97 | + |
| 98 | +=== Web Assets |
| 99 | +Web assets are bundled up inside the Jar and copied out by the Ruby converter. |
| 100 | +The following web assets are used: |
| 101 | + |
| 102 | +* `site.css` file in the `/css` folder. |
| 103 | +* `setup.js` and `site.js` files in the `/js` folder. |
| 104 | +* Images in the `/img` folder. |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | +==== Build |
| 109 | +The web assets are all build using GulpJS which is invoked via NPM from the Gradle build. |
| 110 | +You can also build the web assets directly using the gulp CLI. |
| 111 | + |
| 112 | +Install it using NPM: |
| 113 | + |
| 114 | +[source,shell] |
| 115 | +---- |
| 116 | +$ npm install |
| 117 | +---- |
| 118 | + |
| 119 | +Then run it with the `build` target: |
| 120 | + |
| 121 | +[source,shell] |
| 122 | +---- |
| 123 | +$ gulp build |
| 124 | +---- |
| 125 | + |
| 126 | +The gulp build will do the usual front-end related tasks such as minification and linting. |
| 127 | +Take a look `gulpfile.js` if you want to see the exact details. |
| 128 | + |
| 129 | + |
| 130 | + |
| 131 | +==== Javascript |
| 132 | +There are two javascript assets produced by the build: |
| 133 | + |
| 134 | +* `setup.js` provides any initial setup and is loaded with a regular `<script>` element. |
| 135 | +* `site.js` provides the majority of the Javascript and is loaded with a `<script async>` element. |
| 136 | + |
| 137 | +The source code used to build these files is in link:src/main/js/setup[`src/main/js/setup`] and link:src/main/js/setup[`src/main/js/site`] respectively. |
| 138 | + |
| 139 | +TIP: The `setup.js` file will block page loading and as such should only be used for critical functionality. |
| 140 | +For example, it includes the dark theme switching logic so that the page doesn't flash when loading. |
| 141 | + |
| 142 | +The following files are used to create the `setup.js` file: |
| 143 | + |
| 144 | +* `layout.js` - Adds a `js` class to the `html` element for CSS to use for Javascript detection. |
| 145 | +* `switchtheme.js` - Provides theme switcher logic |
| 146 | + |
| 147 | +The following files are used to create the `site.js` file: |
| 148 | + |
| 149 | +* `codetools.js` - Provides the copy and fold/unfold buttons |
| 150 | +* `highlight.js` - Provide a HighlightJS bundle |
| 151 | +* `tabs.js` - Provides tab switching support |
| 152 | +* `toc.js` - Updates the table of contents when scrolling |
| 153 | + |
| 154 | + |
| 155 | + |
| 156 | +==== CSS |
| 157 | +The single `site.css` file is build from a number of smaller CSS files. |
| 158 | +CSS files can be found in link:src/main/css[`src/main/css`]. |
| 159 | +PostCSS is used to follow `@Import` declarations and create a single file. |
| 160 | + |
| 161 | +Although it's a little overkill for this project, CSS files are organized using the https://www.freecodecamp.org/news/managing-large-s-css-projects-using-the-inverted-triangle-architecture-3c03e4b1e6df/[inverted triangle] architecture. |
| 162 | + |
| 163 | + |
| 164 | +---- |
| 165 | +-------------- _ |
| 166 | +\ / __ settings : (settings.css, settings-dark.css) |
| 167 | + \ / ___ tools : (none) |
| 168 | + \ / ____ generic : (generic.css) |
| 169 | + \ / _____ elements : (elements.css) |
| 170 | + \ / ______ objects : (none) |
| 171 | + \ / _______ components : (components.css) |
| 172 | + \/ _________utilities : (none) |
| 173 | +---- |
| 174 | + |
| 175 | + |
| 176 | + |
| 177 | +===== CSS Variables |
| 178 | +CSS variables are used extensively for colors and variable styling. |
| 179 | +The `settings.css` file contains initial settings and `settings-dark.css` provides dark-mode overrides. |
| 180 | + |
| 181 | +Variables are usually scoped to a specific area and then reference a more generic value. |
| 182 | +For example, `--toc-font-color` is the font color of the TOC. |
| 183 | +It has the value `var(--body-font-color)` which references the general body font color. |
| 184 | + |
| 185 | + |
| 186 | + |
| 187 | +==== Images |
| 188 | +Images are available in the link:src/main/img[`src/main/img`] folder. |
| 189 | +It's best to use SVG images as much as possible. |
| 190 | + |
| 191 | +A single `octicons-16.svg` file provides all the 16x16 icons used by the CSS. |
| 192 | +This file contains a subset of the icons from https://github.com/primer/octicons. |
| 193 | + |
| 194 | + |
| 195 | + |
| 196 | +==== Hacking on the web assets |
| 197 | +If you need to work on the web assets you can run the following Gradle task: |
| 198 | + |
| 199 | +[source,shell] |
| 200 | +---- |
| 201 | +$ ./gradlew dev |
| 202 | +---- |
| 203 | + |
| 204 | +Alternatively you can generate some test HTML and the run `gulp` directly: |
| 205 | + |
| 206 | +[source,shell] |
| 207 | +---- |
| 208 | +$ ./gradlew convertTestAsciidoc |
| 209 | +$ gulp dev |
| 210 | +---- |
| 211 | + |
| 212 | +NOTE: The `convertTestAsciidoc` Gradle task will convert the contents of the link:src/test/asciidoc[`src/test/asciidoc`] directory. |
| 213 | + |
| 214 | +The `dev` task will start a server at `http://localhost:8080` and watch the source files for changes. |
| 215 | +Saving any source file will trigger a rebuild and "live reload". |
| 216 | + |
| 217 | + |
| 218 | + |
| 219 | +=== Formatting |
| 220 | +Java, Javascipt and CSS files can be formatted by running `./gradlew format`. |
| 221 | +Java files are formatted using `spring-javaformat`. |
| 222 | +Other files are formatted using https://prettier.io/[prettier]. |
0 commit comments