There are two issues with ToC:
1. T307691: There are content types like JS which are "parsed as wikitext" (for categories, etc) but don't "really" have sections, and shouldn't have a TOC displayed even if you randomly find `===` in the text.
2. T294950: Some skins now generate the ToC in the UX from `ParserOutput::getSections()` not the ToC HTML. However, this *always* contains data, even if `$enoughToc` (affected by `__NOTOC__`, `__FORCETOC__`, the number of sections in the article, etc) is false. There's no way to determine whether the section data should be rendered by the UX, other than looking to see if `ParserOutput::getTOCHTML()` is empty (which is discouraged, because of {T293513})
The plan is:
1. Add a "showTOC" flag to `ParserOutput`. This will be set to mirror `$enoughToc` in the parser, and will indicate to consumers whether the TOC should be shown (even if `getSections()` contains content, the TOC should sometimes be hidden).
2. Add a `suppressToc` option to `ParserOptions` for code types. This will act like an implicit __NOTOC__ aka suppress `showTOC` in the ParserOutput *and* ensure that `ParserOutput::getSections()` is empty, ie indicate to users that this content type doesn't have any "real" sections in it.
There's a patch for {T294950} already which adds "hideTOC" to the action=parse output, using "`getTOCHTML` is empty" as its criterion. **Unfortunately I had a rethink** and decided to swap the sense of "hideTOC" to "showTOC" in order to better support consistent ParserOutput flag merge semantics ("the TOC should be shown if *any* ParserOutput wants the TOC shown", which is how the existing logic works). We'll need to transition from "hidetoc" to "showtoc" in the API result, and then (after a parser cache "expiration time" in order to ensure that the ParserCache is properly populated with SHOW_TOC flags where appropriate) we'll update the patch to use `ParserOutput::getFlag(ParserOutputFlags::SHOW_TOC)` instead of `getTOCHTML`.