Skip to content

Commit 5ef27ba

Browse files
philwebbrwinch
andcommitted
Add 'javadoc' inline macro extension
Closes gh-14 Co-authored-by: Rob Winch <[email protected]>
1 parent c467e8a commit 5ef27ba

File tree

4 files changed

+470
-0
lines changed

4 files changed

+470
-0
lines changed

README.adoc

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,101 @@ sectid-level-separator (default: .):: The character that must be used to separat
565565

566566
All IDs must be lowercase, must start with an alphabetic character, and may only contain alphanumeric characters aside from the aforementioned separators.
567567

568+
=== Javadoc
569+
570+
*require name:* @springio/asciidoctor-extensions/javadoc-extension
571+
572+
The javadoc extension allows you to quickly create links to javadoc sites.
573+
For example, `javadoc:com.example.MyClass[]` will create a link to `xref:attachment$api/java/com/example/MyClass.html` with the text `MyClass`.
574+
575+
==== Syntax
576+
577+
The following format can be used when declaring a javadoc link:
578+
579+
----
580+
[<location>]<class-reference>[#<anchor>]
581+
----
582+
583+
Only `<class-reference>` is mandatory, and it must be the fully qualified name of the class to link to.
584+
For example, `com.example.MyClass`.
585+
References to inner-classes should use `$` notation instead of `.`.
586+
For example, `com.example.MyClass$Builder`.
587+
588+
If a `<location>` is specified, it must end with `/`.
589+
590+
Any `<anchor>` must exactly match the anchor in the corresponding javadoc page.
591+
592+
==== Locations
593+
594+
Unless otherwise overridden, the default javadoc location will be `xref:attachment$api/java`.
595+
If you want a different default, you can set the `javadoc-location` document attribute.
596+
For example, you can set `javadoc-location` to `xref:api:java` if you publish javadoc under a `api` Antora module.
597+
598+
NOTE: document attributes can be set in your Antora playback under the https://docs.antora.org/antora/latest/playbook/asciidoc-attributes/#attributes-key[attributes key].
599+
600+
You can also override locations on a per-link basis.
601+
For example:
602+
603+
[,asciidoc]
604+
----
605+
= Example
606+
:url-jdk-javadoc: https://docs.oracle.com/en/java/javase/17/docs/api
607+
608+
Please read javadoc:{url-jdk-javadoc}/java.base/java.io.InputStream[]
609+
----
610+
611+
==== Formats and Link Text
612+
613+
By default, a short form of the class name is used as the link text.
614+
For example, if you link to `com.example.MyClass`, only `MyClass` is used for the link text.
615+
616+
If you want to change the format of the link text, you can use the `format` attribute.
617+
For example, `javadoc:com.example.MyClass[format=full]` will use `com.example.MyClass` as the link text.
618+
619+
The following formats are supported:
620+
621+
[cols="1,1,3"]
622+
|===
623+
| Name | Description | Example
624+
625+
| `short` (default)
626+
| The short class name
627+
| `com.example.MyClass$Builder` -> `MyClass.Builder`
628+
629+
| `full`
630+
| The fully-qualified class name
631+
| `com.example.MyClass$Builder` -> `com.example.MyClass.Builder`
632+
633+
| `annotation`
634+
| The short class name prefixed with `@`
635+
| `com.example.MyAnnotation` -> `@MyAnnotation`
636+
|===
637+
638+
TIP: You can change the default format by setting a `javadoc-format` document attribute.
639+
This can be done site-wide, or on a page-by-page basis.
640+
641+
You can also specify directly specify link text if the existing formats are not suitable:
642+
643+
[,asciidoc]
644+
----
645+
See javadoc:com.example.MyClass$Builder[Builder] for details.
646+
----
647+
648+
NOTE: The link text is _always_ wrapped in a `<code>` block so you should not use backticks.
649+
650+
==== Anchors
651+
652+
Anchors may be used to link to a specific part of a javadoc page.
653+
The anchor link must exactly match the link in the target page.
654+
For example, `javadoc:com.example.MyClass#myMethod(java.lang.String)`
655+
656+
When an anchor is specified, the link text will include a readable version.
657+
The example above would render the link text `MyClass.myMethod(String)`.
658+
659+
==== UI Support
660+
661+
All anchors created using the `javadoc` macro will have a role of `apiref` to allow the UI to style them appropriately.
662+
568663
ifndef::env-npm[]
569664
== Development Quickstart
570665

lib/javadoc-extension.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
'use strict'
2+
3+
const toProc = require('./util/to-proc')
4+
5+
const METHOD_REGEX = /(.*)\((.*)\)/
6+
7+
function register (registry, context) {
8+
if (!(registry && context)) return // NOTE only works as scoped extension for now
9+
registry.$groups().$store('springio/javadoc', toProc(createExtensionGroup(context)))
10+
return registry
11+
}
12+
13+
function createExtensionGroup () {
14+
return function () {
15+
this.inlineMacro(function () {
16+
this.named('javadoc')
17+
this.process((parent, target, attrs) => {
18+
const text = process(parent.getDocument(), parseTarget(target), attrs)
19+
return this.createInline(parent, 'quoted', text, {
20+
type: 'monospaced',
21+
})
22+
})
23+
})
24+
}
25+
}
26+
27+
function parseTarget (target) {
28+
target = target.replaceAll('&#8230;&#8203;', '...')
29+
const lastSlash = target.lastIndexOf('/')
30+
const location = lastSlash !== -1 ? target.substring(0, lastSlash) : undefined
31+
const reference = lastSlash !== -1 ? target.substring(lastSlash + 1, target.length) : target
32+
const lastHash = reference.lastIndexOf('#')
33+
const classReference = lastHash !== -1 ? reference.substring(0, lastHash) : reference
34+
const anchor = lastHash !== -1 ? reference.substring(lastHash + 1, reference.length) : undefined
35+
return { location, classReference, anchor }
36+
}
37+
38+
function process (document, target, attrs) {
39+
const location = target.location || document.getAttribute('javadoc-location', 'xref:attachment$api/java')
40+
const format = attrs.format || document.getAttribute('javadoc-format', 'short')
41+
const linkLocation = link(location, target)
42+
const linkDescription = applyFormat(target, format, attrs.$positional)
43+
return `${linkLocation}['${linkDescription}',role=apiref]`
44+
}
45+
46+
function link (location, target) {
47+
let link = location
48+
link = !link.endsWith('/') ? link + '/' : link
49+
link += target.classReference.replaceAll('.', '/').replaceAll('$', '.') + '.html'
50+
if (target.anchor) link += '#' + target.anchor
51+
return link
52+
}
53+
54+
function applyFormat (target, format, positionalAttrs, annotationAnchor) {
55+
if (positionalAttrs?.[0]) return positionalAttrs?.[0]
56+
switch (format) {
57+
case 'full':
58+
return className(target.classReference, 'full') + anchorText(target.anchor, format, annotationAnchor)
59+
case 'annotation':
60+
return '@' + className(target.classReference, 'short') + anchorText(target.anchor, format)
61+
default:
62+
return className(target.classReference, 'short') + anchorText(target.anchor, format)
63+
}
64+
}
65+
66+
function anchorText (anchor, format, annotationAnchor) {
67+
if (!anchor) return ''
68+
if (format === 'annotation' || annotationAnchor) anchor = anchor.replaceAll('()', '')
69+
const methodMatch = METHOD_REGEX.exec(anchor)
70+
if (methodMatch) {
71+
return '.' + methodText(methodMatch[1], methodMatch[2], format)
72+
}
73+
return '.' + anchor
74+
}
75+
76+
function methodText (name, params, format) {
77+
const varargs = params.endsWith('...')
78+
if (varargs) params = params.substring(0, params.length - 3)
79+
return (
80+
name +
81+
'(' +
82+
params
83+
.split(',')
84+
.map((name) => className(name, format))
85+
.join(', ') +
86+
(!varargs ? ')' : '...)')
87+
)
88+
}
89+
90+
function className (classReference, format) {
91+
if (format !== 'full') classReference = classReference.split('.').slice(-1)[0]
92+
return classReference.replaceAll('$', '.')
93+
}
94+
95+
module.exports = { register, createExtensionGroup }

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"./code-folding-extension": "./lib/code-folding-extension.js",
4343
"./configuration-properties-extension": "./lib/configuration-properties-extension.js",
4444
"./include-code-extension": "./lib/include-code-extension.js",
45+
"./javadoc-extension": "./lib/javadoc-extension.js",
4546
"./section-ids-extension": "./lib/section-ids-extension.js"
4647
},
4748
"imports": {

0 commit comments

Comments
 (0)