Skip to content

fix(docs): javadoc and XML docs render Markdown emphasis as tags (#404) - #407

Merged
mario4tier merged 1 commit into
TA-Lib:devfrom
kevinlincg:fix/404-doc-emphasis
Sep 8, 2026
Merged

fix(docs): javadoc and XML docs render Markdown emphasis as tags (#404)#407
mario4tier merged 1 commit into
TA-Lib:devfrom
kevinlincg:fix/404-doc-emphasis

Conversation

@kevinlincg

Copy link
Copy Markdown
Collaborator

Fixes the half of #404 the issue calls independently landable: inline emphasis
in the Java and C# doc targets. The ## Formula half is untouched — see below.

What shipped

jdoc and csdoc converted backtick spans and inline links but not
**bold**/*italic*, so those reached the reader as asterisks. All three
escapers (java_doc, csharp_doc, csharp_stream) now delegate the inline
markup to one backends::common::render_inline, so the two C# tiers — which may
not reach into each other — cannot drift apart on it.

Emphasis is recognized only when it pairs, only outside a code span, and only at
an intraword-free boundary flanking non-space. Anything else is prose and is
escaped exactly as before: the corpus multiplies with * (factor = 4*ATR) and
names parameters with it (optInROC*Period).

Measured on 263be4a: 16 bold / 41 italic delimiters in Core.java, 16 /
40
in Core_*.cs. The issue reports 39 and 38 italics; the two extra here are
the same class and every one I checked is a real delimiter, so I have not tried
to reconcile the counts — nothing keys off them.

Rust is untouched by construction: it never called these escapers.

Gate, and its control

doc_emphasis_suite sweeps every documented function's rendered Java and C#
doc blocks — both precisions, plus the lookback — and fails on a paired
delimiter outside a code span.

It reads the emitters' output, not the generated files. A generated file also
carries the C source's own changelog header verbatim (IMI's Fix #112: … a *successful* call), which is not Markdown and must not be converted; reading the
emitter directly is what tells those apart. My first draft scanned the files and
reported 982 phantom italics in Java, because a Javadoc line's own leading *
reads as an opener — that failure is recorded in the suite's comments.

Verified against a control rather than assumed: with the escaper change
reverted and everything else in place, the sweep reports 116 lines and the probe
test goes red.
Two more directions are pinned, because the obvious over-fix —
convert every * — would silently rewrite parameter names and regress the one
backend that was already right:

  • a code span keeps its asterisks (COPPOCK);
  • Rust keeps its authored Markdown (CMOU).

Nothing else can see this class: javadoc -Xdoclint:all,-missing (what
pom.xml enforces) and csc under -warnaserror with
GenerateDocumentationFile both accept literal Markdown without a diagnostic,
and regen-check agrees with whatever the emitter emits.

Deliberately not in this PR

The ## Formula block. split_formula_note splits only on a closing $$,
which 2 of 150 sections carry, so the other 148 hand their trailing prose to the
emitters as preformatted text — that is where #404's surviving backticks and
Markdown links live. It changes what 148 functions render as a formula in four
backends, and the issue asks for its own before/after diff review, so it is not
folded in here. The suite's module comment says so at the point where someone
would otherwise widen the gate and find it red for a reason this PR did not
cause.

Verification

  • generator tests: 33 suites, 0 failures
  • scripts/build.py generate, idempotent on a second run
  • C and Rust output unchanged; only output/java (27 files) and
    output/csharp (24) moved, line-for-line
  • clippy --all-targets -D warnings: clean

Not verified here, and it is not the falsifying path: I have no working JDK
or a .NET SDK that can target this project, so I did not run javadoc or csc
on the regenerated sources. What this change writes is <b>/<i> inside doc
comments those two toolchains already accept everywhere else in the same files —
and per the issue, neither emits a diagnostic for the unconverted form either,
so a compile would not have been the thing that told us. The discriminating
check is the sweep plus its control, which is in the PR.

…Lib#404)

The canonical `input/<name>/<name>.md` is Markdown, and Rust's doc target is
Markdown too, so rustdoc renders it. Java's target is HTML and C#'s is XML;
`jdoc` and `csdoc` converted backtick spans and inline links but not `**bold**`
or `*italic*`, so those reached the reader as asterisks — in the published
javadoc, the NuGet XML docs and every IDE hover.

Measured on 84266e7: 16 bold and 41 italic delimiters in `Core.java`, 16 and
40 in `Core_*.cs`. (TA-Lib#404 reports 39 and 38 italics; the two extra here are the
same class, and every one I looked at is a real delimiter — the count is not
what the fix keys off.)

Both escapers gained the conversion in place, and both ask
`backends::common::emphasis_open` what counts, so the HTML and XML targets keep
their own tags but cannot come to disagree about the rule. Emphasis is
recognized only when it pairs, only outside a code span, and only at a boundary
that flanks non-space without splitting a word or continuing an asterisk run; an
asterisk failing any of those is prose and is escaped as before. The corpus
multiplies with `*` (`factor = 4*ATR`) and names parameters with it
(`optInROC*Period`), and neither is emphasis.

Rust is untouched by construction: it never called these escapers.

Not in scope, deliberately: the `## Formula` block. `split_formula_note` splits
only on a closing `$$`, which 2 of 150 sections carry, so the other 148 hand
their trailing prose to the emitters as preformatted text — that is where TA-Lib#404's
surviving backticks and Markdown links live. It changes what 148 functions
render as a formula in four backends and wants its own before/after review.

Gate: `doc_emphasis_suite` sweeps every documented function's rendered Java and
C# doc blocks in both precisions plus the lookback, and fails on a paired
delimiter outside a code span. It reads the emitters' output rather than the
generated files on purpose: a generated file also carries the C source's own
changelog header verbatim (IMI's `Fix TA-Lib#112: … a *successful* call`), which is
not Markdown and must not be converted.

Verified against a control rather than assumed: with the escaper change reverted
and everything else in place, the sweep reports 114 lines and the probe test goes
red. Three more directions are pinned, each in the direction a plausible
over-fix would break:

  - a code span keeps its asterisks (COPPOCK), and
  - Rust keeps its authored Markdown (CMOU), because converting every `*` would
    rewrite parameter names and regress the one backend already right;
  - a Markdown link still becomes an anchor (CDL2CROWS). The emphasis arm runs
    before the `[` arm, so it is the one thing that could swallow a link on the
    way past — and the link conversion's own unit tests would not notice, since
    they exercise the escaper directly on link-only input. The rendered anchor
    count is unchanged at 104 in `Core.java`.

Nothing else can see this class: `javadoc -Xdoclint:all,-missing` (what pom.xml
enforces) and `csc` under `-warnaserror` with `GenerateDocumentationFile` both
accept literal Markdown without a diagnostic, and `regen-check` agrees with
whatever the emitter emits.

Generator tests: 33 suites, 0 failures. clippy --all-targets -D warnings clean.
Output regenerated with `scripts/build.py generate`; C and Rust output
unchanged.

Signed-off-by: Kevin <kaiwei.lin@gmail.com>
@kevinlincg

Copy link
Copy Markdown
Collaborator Author

Rebased onto 84266e75c. The rebase changed the shape of this PR, so it is worth
saying what moved rather than leaving the diff to speak.

e46e97c0a (the inline-link conversion) and the csdoc de-duplication landed on
dev after this was branched. The first version replaced all three escapers with
one shared render_inline; that both fought the de-duplication and — more to the
point — would have silently dropped the link conversion, because it rewrote
the escaper bodies wholesale and render_inline knew nothing about ](. Every
test in the branch stayed green through that, which is the part worth flagging.

So it is now the smaller change it should have been: both escapers keep their
existing bodies and gain one arm, and only the pairing rule is shared
(backends::common::emphasis_open) so the HTML and XML targets cannot come to
disagree about what counts while each keeps its own tags.

Two things added because of the rebase, not the original defect:

  • links_still_become_anchors — the emphasis arm runs before the [ arm, so it
    is the one thing that could swallow a link on the way past. The link
    conversion's own unit tests exercise the escapers on link-only input and would
    not have noticed. The rendered anchor count in Core.java is unchanged at 104,
    measured against dev.
  • emphasis_open rejects an opener whose previous character is *. The
    escapers consume both asterisks of a ** at once and never ask about the
    second one, so this is unreachable from them — but a helper two callers share
    should not give a different reading depending on who is walking the string, and
    a unit test caught it asking.

The control was re-run on the new base: with the escaper change reverted and
everything else in place, the sweep reports 114 lines and the probe test goes red,
while links_still_become_anchors stays green — which is what says that test
covers a different axis rather than riding along on this one.

@mario4tier
mario4tier merged commit 433a519 into TA-Lib:dev Sep 8, 2026
7 checks passed
@kevinlincg
kevinlincg deleted the fix/404-doc-emphasis branch September 8, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants