sphinx-java-autodoc 0.6.0__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/PKG-INFO +3 -3
  2. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/README.md +2 -2
  3. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/compatibility.rst +5 -3
  4. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/gallery/comments.rst +2 -1
  5. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/gallery/declarations.rst +3 -0
  6. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/gallery/warnings.rst +8 -4
  7. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/javadoc-support.rst +21 -5
  8. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/schema.md +9 -3
  9. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/showcase.rst +4 -2
  10. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/troubleshooting.rst +18 -3
  11. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/usage.rst +13 -5
  12. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/src/demo/Widget.java +4 -0
  13. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/pyproject.toml +1 -1
  14. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/__init__.py +7 -3
  15. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/domain.py +13 -12
  16. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/extractor.py +23 -10
  17. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/java/SphinxDoclet.java +93 -8
  18. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/javadoc.py +9 -4
  19. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/model.py +9 -1
  20. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/render.py +72 -25
  21. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_boundaries.py +66 -0
  22. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_conformance.py +104 -1
  23. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_integration.py +224 -3
  24. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_javadoc.py +15 -0
  25. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_navigation.py +7 -0
  26. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_signatures.py +89 -0
  27. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_tables.py +19 -0
  28. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/.gitignore +0 -0
  29. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/CONTRIBUTING.md +0 -0
  30. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/LICENSE +0 -0
  31. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/SECURITY.md +0 -0
  32. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/adr/0001-jdk-doclet-xml-sphinx-domain.md +0 -0
  33. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/agents/domain.md +0 -0
  34. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/agents/issue-tracker.md +0 -0
  35. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/alternatives.rst +0 -0
  36. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/build-integration.rst +0 -0
  37. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/conf.py +0 -0
  38. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/design.rst +0 -0
  39. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/gallery/directives.rst +0 -0
  40. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/gallery/index.rst +0 -0
  41. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/gallery/inheritance.rst +0 -0
  42. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/gallery/links.rst +0 -0
  43. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/getting-started.rst +0 -0
  44. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/guide.rst +0 -0
  45. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/index.rst +0 -0
  46. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/docs/performance.rst +0 -0
  47. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/README.md +0 -0
  48. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/build-consumer/BuildInfo.java.in +0 -0
  49. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/build-consumer/src/demo/Consumer.java +0 -0
  50. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/dependency/src/vendor/Token.java +0 -0
  51. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/gradle/build.gradle +0 -0
  52. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/gradle/settings.gradle +0 -0
  53. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/maven/pom.xml +0 -0
  54. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/docs/conf.py +0 -0
  55. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/docs/guide.rst +0 -0
  56. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/docs/index.rst +0 -0
  57. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/docs/reference.rst +0 -0
  58. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/src/demo/Label.java +0 -0
  59. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/src/demo/Mode.java +0 -0
  60. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/src/demo/Point.java +0 -0
  61. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/src/demo/Shape.java +0 -0
  62. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/src/demo/Transformer.java +0 -0
  63. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/examples/standalone/src/demo/package-info.java +0 -0
  64. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/__main__.py +0 -0
  65. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/pages.py +0 -0
  66. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/src/sphinx_java_autodoc/static/java-autodoc.css +0 -0
  67. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/benchmark.py +0 -0
  68. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/build_tools_check.py +0 -0
  69. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_generic_throws.py +0 -0
  70. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_options.py +0 -0
  71. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_snippets.py +0 -0
  72. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_sourcepath.py +0 -0
  73. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/test_value.py +0 -0
  74. {sphinx_java_autodoc-0.6.0 → sphinx_java_autodoc-0.7.0}/tests/visual_check.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sphinx-java-autodoc
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Compiler-backed Java API documentation in native Sphinx nodes
5
5
  Project-URL: Documentation, https://r4sky0.github.io/sphinx-java-autodoc/
6
6
  Project-URL: Repository, https://github.com/r4sky0/sphinx-java-autodoc
@@ -52,8 +52,8 @@ for the output.
52
52
 
53
53
  ## Requirements
54
54
 
55
- Python 3.12+, Sphinx 8.2.x or 9.1.x, and **JDK 25 for extraction**. Your library can keep
56
- targeting Java 17 or 21. See
55
+ Python 3.12+, Sphinx 8.2.x, 9.0.x or 9.1.x, and **JDK 25 for extraction**. Your library
56
+ can keep targeting Java 17 or 21. See
57
57
  [compatibility and limits](https://r4sky0.github.io/sphinx-java-autodoc/compatibility.html).
58
58
 
59
59
  ## Quick start
@@ -21,8 +21,8 @@ for the output.
21
21
 
22
22
  ## Requirements
23
23
 
24
- Python 3.12+, Sphinx 8.2.x or 9.1.x, and **JDK 25 for extraction**. Your library can keep
25
- targeting Java 17 or 21. See
24
+ Python 3.12+, Sphinx 8.2.x, 9.0.x or 9.1.x, and **JDK 25 for extraction**. Your library
25
+ can keep targeting Java 17 or 21. See
26
26
  [compatibility and limits](https://r4sky0.github.io/sphinx-java-autodoc/compatibility.html).
27
27
 
28
28
  ## Quick start
@@ -25,8 +25,9 @@ Requirements and tested versions
25
25
  - 3.12+
26
26
  - 3.12, 3.13 and 3.14
27
27
  * - Sphinx
28
- - 8.2.x and 9.1.x
28
+ - 8.2.x, 9.0.x and 9.1.x
29
29
  - 9.1.0, with the Docutils version it installs (0.22.4); the test suite on 8.2.3
30
+ and on 9.0.4 with Docutils 0.22.4
30
31
  * - Operating system
31
32
  - Platform-neutral
32
33
  - Linux, macOS and Windows in GitHub Actions
@@ -57,8 +58,9 @@ Known limits
57
58
  * Traditional Javadoc comments and plain inline ``{@snippet}`` bodies are
58
59
  supported; see :doc:`javadoc-support`. Markdown comments (``///``), external or
59
60
  hybrid snippets, snippet regions, IDs and markup, and unsupported tags warn. The
60
- HTML subset excludes definition lists, headings, images, presentational attributes,
61
- ``<th>`` styling outside table headers, and local documentation assets.
61
+ HTML subset excludes images, presentational attributes, ``<th>`` styling outside
62
+ table headers, and local documentation assets. Headings become rubrics, outside
63
+ the page's table of contents.
62
64
  * Only declared members are shown. Non-overridden inherited methods stay on their
63
65
  ancestor's page. Compiler-generated record and enum methods are listed, but the
64
66
  standard doclet's generated prose for them is not synthesized.
@@ -11,7 +11,8 @@ HTML, inline tags and snippets
11
11
  One class comment uses most of the supported content: paragraphs, emphasis, nested
12
12
  lists, ``<pre>{@code ...}</pre>`` blocks, line breaks, external links, an inline
13
13
  ``{@snippet}``, a table with a caption, ``{@value}``, ``{@link}`` and
14
- ``{@linkplain}``, and the ``@see`` and ``@since`` tags.
14
+ ``{@linkplain}``, a heading, a definition list, ``<sup>``, ``<kbd>``,
15
+ ``{@systemProperty}``, and the ``@see`` and ``@since`` tags.
15
16
 
16
17
  .. literalinclude:: ../../examples/standalone/src/demo/Widget.java
17
18
  :language: java
@@ -3,6 +3,9 @@ Declarations and signatures
3
3
 
4
4
  Signatures come from the compiler, so they show exactly what JDK 25 accepts. Type
5
5
  names in signatures link to their documentation, here or in external Javadoc.
6
+ Modifiers are those the standard doclet shows: it leaves out implied ones, such as
7
+ ``public`` on interface members, ``abstract`` on interfaces and ``final`` on records
8
+ and enums, and implementation details such as ``synchronized`` and ``native``.
6
9
 
7
10
  Generics, arrays and varargs
8
11
  ----------------------------
@@ -16,19 +16,23 @@ this site builds with ``-W``, so a real warning would fail it.
16
16
  - Markdown documentation comments are not supported
17
17
  - ``java.extract``
18
18
  * - An unknown block tag, such as ``@todo``
19
- - Unsupported block tag UNKNOWN_BLOCK_TAG
19
+ - Unsupported block tag @todo
20
20
  - ``java.extract``
21
21
  * - External snippets, regions or markup
22
22
  - Unsupported snippet attributes or markup
23
23
  - ``java.extract``
24
- * - ``{@link}`` to a symbol the compiler can't find
24
+ * - ``{@link}`` or ``@throws`` naming a symbol the compiler can't find
25
25
  - Unresolved Javadoc reference
26
26
  - ``java.extract``
27
+ * - An override without its own text, such as ``toString``, whose ancestor has
28
+ no source documentation
29
+ - Cannot inherit
30
+ - ``java.inherit``
27
31
  * - ``{@inheritDoc}`` without ancestor source
28
32
  - Cannot resolve inheritDoc
29
33
  - ``java.extract``
30
- * - An HTML element outside the supported subset, such as ``<h3>``
31
- - Unsupported Javadoc HTML <h3>
34
+ * - An HTML element outside the supported subset, such as ``<img>``
35
+ - Unsupported Javadoc HTML <img>
32
36
  - ``java.html``
33
37
  * - A ``:members:`` entry that doesn't exist
34
38
  - Java member ... was not found
@@ -13,17 +13,33 @@ Tags and HTML
13
13
  - JDK notes: ``@apiNote``, ``@implSpec`` and ``@implNote``, with the standard
14
14
  doclet's headings. They are not inherited.
15
15
  - Inline tags: ``code``, ``literal``, ``link``, ``linkplain``, ``value``,
16
- ``inheritDoc``, ``return`` and plain inline ``snippet``.
17
- - HTML: paragraphs, nested lists, tables, ``<pre>``, emphasis, strong text,
18
- ``<br>`` and absolute HTTP(S) or mailto links.
16
+ ``inheritDoc``, ``return`` and plain inline ``snippet``. ``{@summary}`` shows its
17
+ text, ``{@index}`` its term and ``{@systemProperty}`` the property name as code,
18
+ as in the standard doclet; there is no search index entry.
19
+ - HTML: paragraphs, nested lists, definition lists (``<dl>``, ``<dt>``, ``<dd>``),
20
+ tables, ``<pre>``, headings ``<h1>`` to ``<h6>`` as rubrics, ``<br>`` and absolute
21
+ HTTP(S) or mailto links.
22
+ - Inline HTML: emphasis (``<i>``, ``<em>``, ``<var>``, ``<cite>``, ``<dfn>``), strong
23
+ text (``<b>``, ``<strong>``), code (``<code>``, ``<tt>``, ``<kbd>``, ``<samp>``),
24
+ ``<sup>``, ``<sub>`` and ``<small>``, which shows as plain text.
25
+
26
+ ``<pre>`` is highlighted as Java where its text is Java, and shown without a warning
27
+ where it is not, such as a table of results. With a ``lang`` attribute, as in
28
+ snippets, Sphinx warns when the text does not match the language.
19
29
 
20
30
  ``@author``, ``@version`` and the ``@serial`` tags are omitted silently, as in the
21
31
  standard doclet's default output. Other custom tags warn.
22
32
 
33
+ Fields follow the order of the JDK's own documentation, whatever the order of the
34
+ tags: Specified by and Overrides, the notes, then Type parameters, Parameters,
35
+ Returns, Throws, Since and See also.
36
+
23
37
  Text reads as in the standard doclet. A link without a label shows
24
38
  ``Map.Entry``, ``String.format(String, Object...)``, or ``of(L, R)`` for a member of
25
- the same type. Sphinx's smart quotes are off, so quotes and ``...`` stay as written.
26
- ``@throws`` names link to the exception type.
39
+ the same type. A link to a type parameter or a module, such as ``{@link T}`` or
40
+ ``{@link java.base/}``, shows its name or label as code without linking. Sphinx's
41
+ smart quotes are off, so quotes and ``...`` stay as written. ``@throws`` names link
42
+ to the exception type.
27
43
 
28
44
  Constant values
29
45
  ---------------
@@ -23,8 +23,11 @@ not a general XML document interchange service. No external entities are fetched
23
23
  or modifier, `kt` primitive type or `void`, `t` punctuation or spaces, `q` package
24
24
  qualifier, `n` declared name, `tv` type variable, `pname` parameter name, `v` constant
25
25
  or default value, `r` type reference, and `params` containing one `param` per
26
- parameter or record component. `r` carries `target` (canonical ID) and the external
27
- Javadoc `path`, `module` and `fragment`; its text is the nested simple name.
26
+ parameter or record component. Modifiers are those the standard doclet shows,
27
+ without implied ones such as `public` on interface members or `final` on records,
28
+ and without `native`, `synchronized` and `strictfp`. `r` carries `target`
29
+ (canonical ID) and the external Javadoc `path`, `module` and `fragment`; its text
30
+ is the nested simple name.
28
31
  Readers reject unknown tokens and malformed `r` targets.
29
32
  - `doc/part`: `kind` (`body`, `specifiedBy`, `overrides`, `param`, `typeparam`,
30
33
  `return`, `throws`, `see`, `since`, `deprecated`, `apiNote`, `implSpec`, `implNote`)
@@ -64,7 +67,10 @@ not a general XML document interchange service. No external entities are fetched
64
67
  `Map.Entry`, `String.format(String, Object...)` or `of(L, R)` within the same type.
65
68
  An unresolved link has no resolved location and has a diagnostic.
66
69
  - `diagnostic`: symbol-qualified warning text, including unsupported constructs.
67
- Warnings survive cache hits and are re-emitted by Sphinx.
70
+ Warnings survive cache hits and are re-emitted by Sphinx. An optional `kind`
71
+ is `inherit` for an omitted part that no ancestor documents, or `extract`; a
72
+ diagnostic without `kind` is `extract`. Sphinx warns with the kind as subtype,
73
+ such as `java.inherit`. Readers reject other kinds. Additive in schema 1.
68
74
 
69
75
  Identity examples: `example.Outer.Inner`, `example.Outer#FIELD`,
70
76
  `example.Outer#find(java.lang.String,int[])`, `example.Outer#<init>()`.
@@ -17,8 +17,10 @@ JDK links and ``sphinx.ext.linkcode`` for :ref:`source links <source-links>` to
17
17
  GitHub at the pinned commit. For an example of every feature, see the
18
18
  :doc:`gallery/index`. The build reports |showcase-total| warnings:
19
19
 
20
- - |showcase-java.extract| ``java.extract``: overrides of JDK methods that cannot
21
- inherit their documentation, and links to libraries not on the classpath.
20
+ - |showcase-java.inherit| ``java.inherit``: overrides of JDK methods that cannot
21
+ inherit their documentation, because the JDK's sources are not available.
22
+ - |showcase-java.extract| ``java.extract``: links to libraries not on the classpath,
23
+ and ``{@inheritDoc}`` with no ancestor source.
22
24
  - |showcase-java.html| ``java.html``: headings and other unsupported HTML.
23
25
  - |showcase-misc.highlighting_failure| highlighting failures: ``<pre>`` examples that
24
26
  are not Java.
@@ -41,9 +41,24 @@ Unsupported tags, HTML, ``///`` Markdown comments and advanced snippets warn wit
41
41
  the symbol; see :doc:`javadoc-support`. To inherit a dependency's Javadoc, add its
42
42
  sources to ``java_sourcepath``.
43
43
 
44
- Warnings use the ``java.extract``, ``java.html``, ``java.type``, ``java.member``
45
- and related categories. Suppressing a warning does not add the missing content.
46
- Outside Sphinx, ``--warnings-as-errors`` makes extraction diagnostics fail.
44
+ Warnings use the ``java.extract``, ``java.inherit``, ``java.html``, ``java.type``,
45
+ ``java.member`` and related categories. Suppressing a warning does not add the
46
+ missing content. Outside Sphinx, ``--warnings-as-errors`` makes all extraction
47
+ diagnostics fail, whatever their category.
48
+
49
+ An overriding method without its own text for a part warns "Cannot inherit ..."
50
+ as ``java.inherit`` when no ancestor documents that part. This is common for
51
+ overrides of JDK methods such as ``toString``, ``equals`` and ``hashCode``: the
52
+ JDK's sources ship as modules with ``module-info.java``, which ``java_sourcepath``
53
+ rejects, so there is nothing to inherit from. Document the part, or silence only these
54
+ warnings while keeping the others:
55
+
56
+ .. code-block:: python
57
+
58
+ suppress_warnings = ["java.inherit"]
59
+
60
+ An explicit ``{@inheritDoc}`` that cannot be resolved stays ``java.extract``,
61
+ because it leaves an ``[unresolved inheritDoc]`` marker in the output.
47
62
 
48
63
  The extension refuses to overwrite a generated page
49
64
  ---------------------------------------------------
@@ -38,7 +38,8 @@ Set these in ``conf.py``. Paths are relative to ``conf.py``, except
38
38
  - JDK 25 home; empty uses the runtime on ``PATH``.
39
39
  * - ``java_release``
40
40
  - ``""``
41
- - Source/API release; empty uses the JDK default. Tested: 17, 21, 25.
41
+ - Source/API release, such as ``"17"`` or ``17``; empty uses the JDK default.
42
+ Tested: 17, 21, 25.
42
43
  * - ``java_generate``
43
44
  - ``""``
44
45
  - Directory for generated pages, such as ``"api"``. Empty generates no pages.
@@ -128,8 +129,11 @@ Roles
128
129
 
129
130
  ``java:obj`` accepts any kind. Targets are fully qualified: there are no imports
130
131
  or short-name guessing. Parameters are erased, fully qualified types, with ``[]``
131
- for varargs; constructors are ``<init>``. A method without a parameter list
132
- resolves only when it has one overload; otherwise it warns. References inside Java
132
+ for varargs; constructors are ``<init>``. Roles, ``java:auto*`` arguments,
133
+ ``java:autosummary`` lines and ``:members:``/``:exclude-members:`` entries all
134
+ ignore spaces and accept ``...`` for ``[]``, so ``find(java.lang.String, int)``
135
+ works too. A method without a parameter list resolves only when it has one
136
+ overload; otherwise it warns. References inside Java
133
137
  comments are resolved by the compiler as usual.
134
138
 
135
139
  .. _source-links:
@@ -177,8 +181,12 @@ Map package prefixes to Javadoc roots; the longest prefix wins:
177
181
  Javadoc 9+ URL structure; Javadoc 8 anchors are not supported. URLs are built
178
182
  without fetching or checking the remote site.
179
183
 
180
- A role that no source comment references has no module metadata. For those, map
181
- the exact package without ``{module}``:
184
+ A role takes the module and location from the extracted model when the symbol
185
+ appears there: in a comment link, a documented exception or a signature. Other
186
+ roles have no module metadata. For those, map the package, or a prefix of it within one module, without ``{module}``. The type
187
+ name starts at the first capitalized name, as Java naming conventions have it, so
188
+ ``vendor.api.util.Thing.Inner`` under ``vendor.api`` links to
189
+ ``vendor/api/util/Thing.Inner.html``:
182
190
 
183
191
  .. code-block:: python
184
192
 
@@ -29,6 +29,10 @@ import java.util.Map;
29
29
  * <td>Labelled {@value #LABEL}; long names such as
30
30
  * {@code com.example.widgets.configuration.DefaultWidgetLabelProvider} stay inside the table</td></tr>
31
31
  * </table>
32
+ * <h2>Terms</h2>
33
+ * <dl><dt><dfn>Label</dfn></dt><dd>Text shown with each value, up to 2<sup>31</sup> characters.</dd>
34
+ * <dt>Shortcut</dt><dd>Copy with <kbd>Ctrl</kbd>+<kbd>C</kbd>; files go to
35
+ * {@systemProperty user.home}.</dd></dl>
32
36
  * @see Point
33
37
  * @since 1.0
34
38
  */
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sphinx-java-autodoc"
7
- version = "0.6.0"
7
+ version = "0.7.0"
8
8
  description = "Compiler-backed Java API documentation in native Sphinx nodes"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -61,7 +61,9 @@ def prepare(app):
61
61
  app.env.java_model_path = str(model.path)
62
62
  use_model(root)
63
63
  for diagnostic in root.findall("diagnostic"):
64
- LOGGER.warning(diagnostic.text, type="java", subtype="extract")
64
+ # The kind lets suppress_warnings = ["java.inherit"] keep the other warnings.
65
+ subtype = diagnostic.get("kind", "extract")
66
+ LOGGER.warning(diagnostic.text, type="java", subtype=subtype)
65
67
  if config.java_generate:
66
68
  directory = (Path(app.srcdir) / config.java_generate).resolve()
67
69
  if (
@@ -95,7 +97,6 @@ def setup(app):
95
97
  "java_encoding": "UTF-8",
96
98
  "java_exclude_packages": [],
97
99
  "java_jdk": "",
98
- "java_release": "",
99
100
  "java_model": "",
100
101
  "java_generate": "",
101
102
  "java_visibility": "protected",
@@ -103,13 +104,16 @@ def setup(app):
103
104
  "java_maximum_signature_line_length": None,
104
105
  }.items():
105
106
  app.add_config_value(name, default, "env")
107
+ # A release is often written as a number, such as java_release = 17.
108
+ app.add_config_value("java_release", "", "env", types=frozenset({str, int}))
106
109
  app.add_domain(JavaDomain)
107
110
  add_linkcode_domain("java", ["fullname", "source", "line"])
108
111
  app.add_css_file("java-autodoc.css")
109
112
  app.connect("builder-inited", add_static_path)
110
113
  app.connect("builder-inited", prepare)
111
114
  app.connect("env-get-outdated", outdated)
112
- app.connect("missing-reference", quiet_reference)
115
+ # After intersphinx (priority 500), whatever the extension order.
116
+ app.connect("missing-reference", quiet_reference, priority=900)
113
117
  return {
114
118
  "version": VERSION,
115
119
  "env_version": 4,
@@ -118,15 +118,10 @@ def summary_type(element) -> list[nodes.Node]:
118
118
  else:
119
119
  tokens.append(sig[i])
120
120
  i += 1
121
- owner = SYMBOLS.get(element.get("id").partition("#")[0])
122
- interface = owner is not None and owner.get("kind") in {
123
- "interface",
124
- "annotation_type",
125
- }
126
121
  modifiers = []
127
122
  while tokens and (tokens[0].tag == "k" or tokens[0].text == " "):
128
123
  text = tokens.pop(0).text
129
- if text in SUMMARY_MODIFIERS and not (interface and text == "abstract"):
124
+ if text in SUMMARY_MODIFIERS:
130
125
  modifiers.append(text)
131
126
  if tokens and tokens[-1].tag == "t" and tokens[-1].text == " ":
132
127
  tokens.pop()
@@ -148,6 +143,11 @@ def display_name(symbol: str) -> str:
148
143
  return f"{owner}.{member_label(symbol)}" if member else symbol
149
144
 
150
145
 
146
+ def canonical(spelling: str) -> str:
147
+ """A hand-written symbol as a model ID: no spaces, and varargs ``...`` as ``[]``."""
148
+ return re.sub(r"\s+", "", spelling).replace("...", "[]")
149
+
150
+
151
151
  class JavaDirective(SphinxDirective):
152
152
  def visible(self, element) -> bool:
153
153
  return visible(
@@ -246,10 +246,10 @@ class AutoClass(JavaDirective):
246
246
  if "members" in self.options:
247
247
  # Semicolons allow exact signatures containing commas.
248
248
  selected = {
249
- s.strip() for s in self.options["members"].split(";") if s.strip()
249
+ canonical(s) for s in self.options["members"].split(";") if s.strip()
250
250
  }
251
251
  excluded = {
252
- s.strip()
252
+ canonical(s)
253
253
  for s in self.options.get("exclude-members", "").split(";")
254
254
  if s.strip()
255
255
  }
@@ -287,8 +287,8 @@ class AutoMember(JavaDirective):
287
287
  option_spec = {"no-index": directives.flag}
288
288
 
289
289
  def run(self):
290
- symbol = re.sub(r"\s+", "", self.arguments[0])
291
- element = self.lookup(symbol.replace("...", "[]"), ("member",))
290
+ symbol = canonical(self.arguments[0])
291
+ element = self.lookup(symbol, ("member",))
292
292
  if element is None:
293
293
  self.missing("member", symbol, "member")
294
294
  return []
@@ -343,7 +343,7 @@ class AutoSummary(JavaDirective):
343
343
  table = nodes.table("", classes=["autosummary", "longtable", "java"])
344
344
  rows = []
345
345
  for line in self.content:
346
- symbol = re.sub(r"\s+", "", line)
346
+ symbol = canonical(line)
347
347
  if not symbol:
348
348
  continue
349
349
  element = self.lookup(symbol)
@@ -441,8 +441,9 @@ class JavaDomain(Domain):
441
441
  yield symbol, display_name(symbol), kind, docname, target, 0
442
442
 
443
443
  def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
444
+ # External Javadoc fragments keep the spelling's varargs.
444
445
  spelling = re.sub(r"\s+", "", target)
445
- target = spelling.replace("...", "[]")
446
+ target = canonical(target)
446
447
  objects = self.data["objects"]
447
448
  # Only member names can omit their parameter list.
448
449
  if target not in objects and "#" in target and "(" not in target:
@@ -7,6 +7,7 @@ import json
7
7
  import os
8
8
  from pathlib import Path
9
9
  import re
10
+ import secrets
10
11
  import shutil
11
12
  import subprocess
12
13
  import tempfile
@@ -16,9 +17,11 @@ from sphinx.errors import ExtensionError
16
17
 
17
18
  from .model import Model, read_model
18
19
 
19
- VERSION = "0.6.0" # x-release-please-version
20
+ VERSION = "0.7.0" # x-release-please-version
20
21
  DOCLET = Path(__file__).parent / "java" / "SphinxDoclet.java"
21
22
  PACKAGE = re.compile(r"[^\W\d]\w*(?:\.[^\W\d]\w*)*")
23
+ # The JVM announces options from variables such as JAVA_TOOL_OPTIONS on stderr.
24
+ JVM_NOTICE = re.compile(r"(NOTE: )?Picked up \w+:")
22
25
 
23
26
 
24
27
  def run(arguments: list[str], *, cwd: Path | None = None) -> str:
@@ -50,15 +53,20 @@ def atomic_write(path: Path, data: bytes) -> None:
50
53
  path.parent.mkdir(parents=True, exist_ok=True)
51
54
  if path.exists() and path.read_bytes() == data:
52
55
  return
53
- with tempfile.NamedTemporaryFile(dir=path.parent, delete=False) as stream:
54
- temporary = Path(stream.name)
55
- try:
56
+ temporary = path.with_name(f".{path.name}.{secrets.token_hex(8)}.tmp")
57
+ # O_EXCL refuses an existing file or planted symlink; the umask applies to 0o666.
58
+ # Opened before the try, so the cleanup never removes a file it did not create.
59
+ fd = os.open(
60
+ temporary,
61
+ os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_BINARY", 0),
62
+ 0o666,
63
+ )
64
+ try:
65
+ with os.fdopen(fd, "wb") as stream:
56
66
  stream.write(data)
57
- stream.flush()
58
- stream.close()
59
- os.replace(temporary, path)
60
- finally:
61
- temporary.unlink(missing_ok=True)
67
+ os.replace(temporary, path)
68
+ finally:
69
+ temporary.unlink(missing_ok=True)
62
70
 
63
71
 
64
72
  def extract(
@@ -243,7 +251,12 @@ def extract(
243
251
  ),
244
252
  encoding="utf-8",
245
253
  )
246
- diagnostics = run([tools["javadoc"], "@" + str(argfile)], cwd=work)
254
+ printed = run([tools["javadoc"], "@" + str(argfile)], cwd=work)
255
+ diagnostics = "".join(
256
+ line
257
+ for line in printed.splitlines(keepends=True)
258
+ if not JVM_NOTICE.match(line)
259
+ )
247
260
  root = read_model(output)
248
261
  root.set("extractor", VERSION)
249
262
  if diagnostics.strip():
@@ -46,7 +46,8 @@ public final class SphinxDoclet implements Doclet {
46
46
  private Types types;
47
47
  private Path output;
48
48
  private List<String> excluded = List.of();
49
- private final Set<String> warnings = new TreeSet<>();
49
+ // Diagnostic text and its kind: "inherit" for an omitted part no ancestor documents.
50
+ private final Map<String, String> warnings = new TreeMap<>();
50
51
  private final Map<Element, Map<String, Part>> comments = new HashMap<>();
51
52
 
52
53
  /** Documentation content together with the declaration whose comment supplied it. */
@@ -214,10 +215,17 @@ public final class SphinxDoclet implements Doclet {
214
215
  if (env.getIncludedElements().stream()
215
216
  .noneMatch(
216
217
  e -> excluded(pkg, elements.getPackageOf(e).getQualifiedName().toString()))) {
217
- warnings.add("Excluded package %s matches no source package.".formatted(pkg));
218
+ warnings.put("Excluded package %s matches no source package.".formatted(pkg), "extract");
218
219
  }
219
220
  }
220
- warnings.forEach(warning -> root.addText("diagnostic", warning));
221
+ warnings.forEach(
222
+ (warning, kind) -> {
223
+ var diagnostic = root.add("diagnostic");
224
+ if (!kind.equals("extract")) {
225
+ diagnostic.set("kind", kind);
226
+ }
227
+ diagnostic.node().setTextContent(Xml.safe(warning));
228
+ });
221
229
  var transformer = TransformerFactory.newInstance().newTransformer();
222
230
  transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
223
231
  transformer.setOutputProperty(OutputKeys.INDENT, "yes");
@@ -263,7 +271,12 @@ public final class SphinxDoclet implements Doclet {
263
271
 
264
272
  /** Records a diagnostic; {@code template} is a {@link String#format} pattern. */
265
273
  private void warn(Element owner, String template, Object... args) {
266
- warnings.add(id(owner) + ": " + (args.length == 0 ? template : template.formatted(args)));
274
+ warn("extract", owner, template, args);
275
+ }
276
+
277
+ private void warn(String kind, Element owner, String template, Object... args) {
278
+ warnings.putIfAbsent(
279
+ id(owner) + ": " + (args.length == 0 ? template : template.formatted(args)), kind);
267
280
  }
268
281
 
269
282
  // Declarations and signatures
@@ -307,8 +320,10 @@ public final class SphinxDoclet implements Doclet {
307
320
  sig.addText("t", " ");
308
321
  }
309
322
  for (var modifier : e.getModifiers()) {
310
- sig.addText("k", modifier.toString());
311
- sig.addText("t", " ");
323
+ if (shown(e, modifier)) {
324
+ sig.addText("k", modifier.toString());
325
+ sig.addText("t", " ");
326
+ }
312
327
  }
313
328
  switch (e) {
314
329
  case TypeElement type -> typeSig(sig, type);
@@ -327,6 +342,27 @@ public final class SphinxDoclet implements Doclet {
327
342
  }
328
343
  }
329
344
 
345
+ /**
346
+ * Whether the standard doclet shows the modifier: it leaves out implementation details and
347
+ * modifiers that the declaration's kind implies, such as {@code public} on interface members.
348
+ */
349
+ private static boolean shown(Element e, Modifier modifier) {
350
+ var kind = e.getKind();
351
+ boolean interfaceMember =
352
+ !(e instanceof TypeElement) && e.getEnclosingElement().getKind().isInterface();
353
+ return switch (modifier) {
354
+ case NATIVE, SYNCHRONIZED, STRICTFP -> false;
355
+ case PUBLIC -> !interfaceMember;
356
+ case PROTECTED, PRIVATE, STATIC -> true;
357
+ case ABSTRACT ->
358
+ kind != ElementKind.ENUM
359
+ && !kind.isInterface()
360
+ && !(interfaceMember && e instanceof ExecutableElement);
361
+ case FINAL -> kind != ElementKind.ENUM && kind != ElementKind.RECORD;
362
+ default -> kind != ElementKind.ENUM;
363
+ };
364
+ }
365
+
330
366
  private void typeSig(Xml sig, TypeElement type) {
331
367
  var kind = type.getKind();
332
368
  sig.addText(
@@ -540,6 +576,15 @@ public final class SphinxDoclet implements Doclet {
540
576
  }
541
577
 
542
578
  private Xml declaration(Xml parent, String tag, Element e) {
579
+ try {
580
+ return declarationNode(parent, tag, e);
581
+ } catch (RuntimeException ex) {
582
+ // Names the declaration in "Sphinx extraction failed", so its comment can be found.
583
+ throw new IllegalStateException(id(e) + ": " + ex, ex);
584
+ }
585
+ }
586
+
587
+ private Xml declarationNode(Xml parent, String tag, Element e) {
543
588
  var node =
544
589
  parent
545
590
  .add(tag)
@@ -602,7 +647,10 @@ public final class SphinxDoclet implements Doclet {
602
647
  result.put(custom.getTagName() + ":" + note++, new Part(e, "", custom.getContent()));
603
648
  default -> {
604
649
  if (!OMITTED.contains(tag.getKind())) {
605
- warn(e, "Unsupported block tag %s; retain it in handwritten guides.", tag.getKind());
650
+ // The tag as written, such as @todo, rather than its kind UNKNOWN_BLOCK_TAG.
651
+ Object name =
652
+ tag instanceof BlockTagTree block ? "@" + block.getTagName() : tag.getKind();
653
+ warn(e, "Unsupported block tag %s; retain it in handwritten guides.", name);
606
654
  }
607
655
  }
608
656
  }
@@ -638,6 +686,13 @@ public final class SphinxDoclet implements Doclet {
638
686
 
639
687
  private void putThrows(Map<String, Part> result, Element e, ThrowsTree thrown) {
640
688
  var target = resolve(e, thrown.getExceptionName());
689
+ if (target == null) {
690
+ // As for {@link}; the part keeps the name as written.
691
+ warn(
692
+ e,
693
+ "Unresolved Javadoc reference %s; check spelling, source paths and classpath.",
694
+ thrown.getExceptionName());
695
+ }
641
696
  String name = target == null ? thrown.getExceptionName().toString() : id(target);
642
697
  // Inheritance must copy every description of the same exception.
643
698
  result.merge(
@@ -815,6 +870,7 @@ public final class SphinxDoclet implements Doclet {
815
870
  if (part == null) {
816
871
  if (method != null) {
817
872
  warn(
873
+ "inherit",
818
874
  e,
819
875
  "Cannot inherit %s; provide the overridden method's source documentation or"
820
876
  + " document this part explicitly.",
@@ -968,6 +1024,16 @@ public final class SphinxDoclet implements Doclet {
968
1024
  case StartElementTree start -> startElement(parent, start);
969
1025
  case EndElementTree end -> parent.add("end").set("name", end.getName().toString());
970
1026
  case InheritDocTree inherit -> inheritDoc(parent, owner, key, inherit, chain);
1027
+ // The standard doclet shows an index term and a summary as text, and a system
1028
+ // property as code. A quoted index term, which may contain spaces, loses its quotes.
1029
+ case IndexTree index -> {
1030
+ String term = index.getSearchTerm().toString();
1031
+ parent.addText(
1032
+ "text", term.matches("\".*\"") ? term.substring(1, term.length() - 1) : term);
1033
+ }
1034
+ case SummaryTree summary -> emit(parent, owner, key, summary.getSummary(), chain);
1035
+ case SystemPropertyTree property ->
1036
+ parent.addText("code", property.getPropertyName().toString());
971
1037
  case ReturnTree ret -> {
972
1038
  parent.addText("text", "Returns ");
973
1039
  emit(parent, owner, "return", ret.getDescription(), chain);
@@ -1023,8 +1089,27 @@ public final class SphinxDoclet implements Doclet {
1023
1089
  parent.addText("literal", "[missing link target]");
1024
1090
  return;
1025
1091
  }
1026
- var link = parent.add("link").set("plain", Boolean.toString(plain));
1027
1092
  var target = resolve(owner, ref);
1093
+ // Type parameters and modules have no page in the model; they stay code text.
1094
+ if (target instanceof TypeParameterElement || target instanceof ModuleElement) {
1095
+ if (!plain) {
1096
+ parent.add("start").set("name", "code").set("closed", "false");
1097
+ }
1098
+ if (label.isEmpty()) {
1099
+ String name =
1100
+ target instanceof ModuleElement module
1101
+ ? module.getQualifiedName().toString()
1102
+ : target.getSimpleName().toString();
1103
+ parent.addText("text", name);
1104
+ } else {
1105
+ emit(parent, owner, "label", label, new HashSet<>());
1106
+ }
1107
+ if (!plain) {
1108
+ parent.add("end").set("name", "code");
1109
+ }
1110
+ return;
1111
+ }
1112
+ var link = parent.add("link").set("plain", Boolean.toString(plain));
1028
1113
  link.set("target", target == null ? ref.toString() : id(target));
1029
1114
  if (target == null) {
1030
1115
  warn(