Skip to content

Parse HTML properly in Scaladoc - #25681

Merged
mbovel merged 4 commits into
scala:mainfrom
dotty-staging:s/m6
Apr 16, 2026
Merged

Parse HTML properly in Scaladoc#25681
mbovel merged 4 commits into
scala:mainfrom
dotty-staging:s/m6

Conversation

@SolalPirelli

Copy link
Copy Markdown
Contributor

Avoid basic stuff like letting <script> through.

Obviously Scaladoc content is in the hands of the user, but we should at least not do HTML with regexes.

Obligatory SO post: https://stackoverflow.com/a/1732454

How much have you relied on LLM-based tools in this contribution?

not

How was the solution tested?

new tests

Comment thread project/Build.scala
lazy val commonBootstrappedSettings = commonDottySettings ++ Seq(
// To enable support of scaladoc and language-server projects you need to change this to true
bspEnabled := false,
bspEnabled := enableBspAllProjects,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no reason not to do this IMHO

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a very strong reason: you don't want your IDE to recompile every bootstrapped project from scratch every time you change one line in the compiler!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow. If you deliberately enable this off-by-default option, why not recompile whatever's necessary in that case?

If there's an issue we should at the very least put it on the same plan as enableBspAllProjects and make it a variable that's easy to toggle without editing the build file.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah never mind, I saw the removal of false and panicked. Using enableBspAllProjects seems accurate.

*/
class CaretTest extends BaseHtmlTest:

private def docHtml(cls: String, syntax: String = "markdown"): String =

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved one level up so the logic can be shared with the new tests

class ScriptWithSpaces

/** <script>alert('hello')</script> */
class FakeSafeScript

@SolalPirelli SolalPirelli Apr 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the character in the comment that your browser probably doesn't render very well is the same char we internally use to mark "safe" HTML tags (why do we have such a char? because IMHO the entire scaladoc parsing stack is too hacky, and should be rewritten to be a single-pass parser... but that's for another day)

val CleanCommentLine =
new Regex("""(?:\s*\*\s?\s?)?(.*)""")

/** Dangerous HTML tags that should be replaced by something safer,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a dangerous use of dangerous, pun intended. Those tags were not the kind of tags one should call dangerous.

/** Safe HTML tags that can be kept. */
val SafeTags =
new Regex("""((&\w+;)|(&#\d+;)|(</?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|cite|code|col|colgroup|dd|del|dfn|em|fieldset|form|hr|img|input|ins|i|kbd|label|legend|link|map|object|optgroup|option|param|pre|q|samp|select|small|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|tr|tt|var)( [^>]*)?/?>))""")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed "safe" tags that are related to user input (why would anyone do this?) or considered terminally deprecated (e.g., acronym)

@SolalPirelli
SolalPirelli requested a review from sjrd April 2, 2026 08:42
@SolalPirelli
SolalPirelli requested a review from mbovel April 8, 2026 11:38

@mbovel mbovel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just report an error and stop if there are invalid tags? Is stripping them silently really better? As a user, I'd rather known as soon as possible if I am using a tag that is not supported. It might also simplify the implementation.

@SolalPirelli

Copy link
Copy Markdown
Contributor Author

@mbovel if you want to propose new behavior for Scaladoc, please go ahead (I'm not sure exactly which process that'd go through), but this PR is continuing the existing behavior while fixing some obviously broken stuff. Let's not let perfect be the enemy of good :)

/**
* Removes HTML tags except simple ones that can be translated or that are definitely harmless,
* translates Scala/Javadoc tags, and generally cleans the input.
* Not the fastest code in the world, and should eventually be replaced by a real parser,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed orally, I'd be interesest what "Not the fastest code in the world" means.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SolalPirelli says the CI time seems similar at least.

insideLink = false
}
index += 1
} else if (index <= text.length - 3 && text(index) == '`' && text(index + 1) == '`' && text(index + 2) == '`') {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't that kind of things be specific to wikidoc or markdown? Are backtricks and [ below interpreted the same in wikidoc and markdown?

result.append(text.substring(index + 1, subStringEndIndex) match {
case "" => "&lt;" // not actually a tag
case "p" | "div" => "\n\n"
case "h1" => "\n= "

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we would translate these to wikidoc markup for them to be translated back to HTML after. What's the point? And how does that work with markdown? I realize this was already done like this before this PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up issue: #25812

@mbovel

mbovel commented Apr 16, 2026

Copy link
Copy Markdown
Member

Well, modulo all things that are weird and were already weird before, I guess it somehow LOTM (looks okayish to me) 😅

@mbovel
mbovel self-requested a review April 16, 2026 08:48
@mbovel
mbovel merged commit 92a4162 into scala:main Apr 16, 2026
72 of 73 checks passed
@mbovel
mbovel deleted the s/m6 branch April 16, 2026 08:48
@WojciechMazur WojciechMazur added the backport:nominated If we agree to backport this PR, replace this tag with "backport:accepted", otherwise delete it. label May 10, 2026
@WojciechMazur WojciechMazur added this to the 3.8.4 milestone May 10, 2026
@WojciechMazur WojciechMazur added backport:accepted This PR needs to be backported, once it's been backported replace this tag by "backport:done" and removed backport:nominated If we agree to backport this PR, replace this tag with "backport:accepted", otherwise delete it. labels May 10, 2026
WojciechMazur added a commit that referenced this pull request May 11, 2026
Backports #25681 to the 3.8.4-RC2.

PR submitted by the release tooling.
[skip ci]
tgodzik added a commit that referenced this pull request May 26, 2026
Avoid basic stuff like letting `<script>` through.

Obviously Scaladoc content is in the hands of the user, but we should at
least not do HTML with regexes.

Obligatory SO post: https://stackoverflow.com/a/1732454

## How much have you relied on LLM-based tools in this contribution?

not

## How was the solution tested?

new tests
[Cherry-picked 92a4162][modified]
@WojciechMazur WojciechMazur added backport:done This PR was successfully backported. and removed backport:accepted This PR needs to be backported, once it's been backported replace this tag by "backport:done" labels Jun 1, 2026
bishabosha pushed a commit to dotty-staging/dotty that referenced this pull request Jun 5, 2026
Avoid basic stuff like letting `<script>` through.

Obviously Scaladoc content is in the hands of the user, but we should at
least not do HTML with regexes.

Obligatory SO post: https://stackoverflow.com/a/1732454

## How much have you relied on LLM-based tools in this contribution?

not

## How was the solution tested?

new tests
alexarchambault pushed a commit to plasmon-scala/scala3 that referenced this pull request Jun 16, 2026
Avoid basic stuff like letting `<script>` through.

Obviously Scaladoc content is in the hands of the user, but we should at
least not do HTML with regexes.

Obligatory SO post: https://stackoverflow.com/a/1732454

## How much have you relied on LLM-based tools in this contribution?

not

## How was the solution tested?

new tests
[Cherry-picked 92a4162]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:done This PR was successfully backported.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants