-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix: Don't break TOC when OpenAPI description includes headers #281
Conversation
a6df7c1
to
f0de06b
Compare
I've verified this works correctly by:
Then amending the gem 'govuk_tech_docs', path: ".." And pointing it to the OpenAPI document as mentioned in alphagov/tdt-documentation#156 (comment). |
Hi @jamietanna, nice work identifying the problem so fast! 🙌 Thanks for the proposed fix, the code changes look fine to me, but I am a bit worried about the user experience if there are situations where some headings have anchor links and some don't. I was wondering if you'd managed to figure out why these headings don't get autogenerated anchor links like other headings? |
Hey @lfdebrux, yes it's due to the OpenAPI document parser library that we use which, when rendering the document doesn't configure the Markdown generator to emit IDs. This is different to the way that Middleman's markdown is generated, which does produce the IDs we need, and right now there's no way to do this. I see our options as:
|
@jamietanna so we don't do any post-processing of the markdown before inserting it into our documents? 😞 |
Hello 👋 I'm the author of the gem and work at GDS. Happy to help try resolve this problem. Am I understanding correctly that the core of this problem is that the tech docs gem expects every h1-6 to have an id attribute, however any markdown data from E.g. You want, for a description of I think the easiest way you can resolve that problem without upstream changes would be to switch from using the So you could change say: tech-docs-gem/lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb Line 2 in bc4bf6d
to <%= render_markdown(info.description) %> Where def render_markdown(text)
redcarpet = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(with_toc_data: false), {})
redcarpet.render(text)
end This would mean you get the ids as the It'd be good to open an issue on the gem, https://github.com/kevindew/openapi3_parser, if this is a feature you expect of the gem. I'm not too sure how contentious header ids are as a Markdown feature (it doesn't seem to be a part of the CommonMarker library) - or if applying it to an OpenAPI doc may mean you risk duplicate ids. |
Thanks Kev, that's really appreciated. That is a good point, that gives us the functionality we want. My only concern is, as far as I know, Redcarpet isn't a CommonMark compliant Markdown geenrator, so we risk consumers not being able to do certain things / having slightly different output than they're expecting. If we're happy with that, I'm happy to amend it, and raise an issue on the repo for visibility? Are we happy with going the approach of using Redcarpet? OpenAPI3 expects the Markdown to be CommonMark, which I don't believe Redcarpet uses, so although we'd get the IDs, there's the risk that |
@kevindew thanks, that's really cool of you to see this and help out! @jamietanna we have our own patched version of the middleman redcarpet generator that we might want to use? https://github.com/alphagov/tech-docs-gem/blob/master/lib/govuk_tech_docs/tech_docs_html_renderer.rb In terms of CommonMark, I think users will expect to see the same behaviour whether writing doc pages or api specs? |
Sounds like a plan re using our version 👍 That's fair - I think if it were me, I'd potentially be using this OpenAPI description with different tools (i.e. it may go onto the API Catalogue or other internal/external tooling, such as rendering inside tools like JIRA, or an IDE) and I'd be expecting a consistent formatting across all of those. It's unlikely that many users will be affected, but the reason CommonMark became a thing is because so many Markdown flavours are inconsistent, so it's possible that people will be affected by quirks that RedCarpet has. I agree that it'd be odd to write a doc page that doesn't render the same as the API docs, and to that I wonder if maybe we should look at using CommonMark everywhere? |
That's an interesting point, worth raising an issue about perhaps! We'd have to think carefully about backwards compatibility of course :/ |
Moving to draft as there's still a bit of work to be done 👍 |
Yeah I get your concern there. The reason I use the commonmarker gem in openapi3_parser is because the OpenAPI spec specifies commonmark. But it doesn't look like the header ids are a feature of a Commonmark (aside: I'm not sure how Github generate them, perhaps they have a post processer) so I think if that bonus feature of markdown is required you'd be best placed to use a different markdown generator. I imagine the amount of headaches you'd get from writing your own post-processor to add ids to Commonmark generated markdown would be much higher than any headaches you'd have of redcarpet spec differences (which I imagine is pretty small, without any significant research) |
f0de06b
to
5b738ab
Compare
Thanks folks, that worked quite nicely, once I managed to inject the render correctly 👍 |
I believe GitHub gets around it by not being CommonMark, but instead using GitHub Flavoured Markdown? |
Sorry, had missed that there were unit tests for this class - I'll sort them, and then put this back out for review 👍 |
Thanks @jamietanna! Once tests are passing I will take a look, I appreciate you taking the time for this! |
Interestingly commonmarker uses Github Flavoured Markdown (https://github.com/github/cmark-gfm) but the header ids aren't a part of the spec: https://github.github.com/gfm/ |
As noted in [0], the ability to render a CommonMark document through OpenAPI specifications' `info.description` is breaking due to how the Table of Contents code works. We'd assumed that the `id` would always be set on headers - by the `TechDocsHTMLRenderer` - but as we've been rendering the markdown through `openapi3_parser`'s CommonMark implementation, these IDs are not being populated. Until the `openapi3_parser` gem supports making this configurable, which is unlikely, due to the way that CommonMark doesn't have this as a default extension, we can instead utilise our `TechDocsHTMLRenderer` to render the headings with IDs, as expected. To do this, we can create a new helper in `ApiReferenceRenderer` which will render the Markdown document as our custom Markdown, which requires we construct the `TechDocsHTMLRenderer` class, which needs the Middleman `ConfigContext` class injected in. As well as the original `info.description` that we'd planned to amend, we can also replace any other CommonMark->HTML rendering at the same time. This means that we won't be using CommonMark, as per the OpenAPI spec, and this is something we'll look to address in alphagov#282. The setup for our tests are now a little more complex, as we're not able to (easily) inject `RedCarpet`, so need to mock a bit more to make it work. [0]: alphagov/tdt-documentation#156
5b738ab
to
29362c9
Compare
As it's possible for the server description to be CommonMark, we should render as Markdown (even though right now we're not actually using CommonMark).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code changes look good, and it works for me! 👍
Thanks again @jamietanna (and @kevindew for the assist).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks for all the hard work on this @jamietanna and everyone.
I'm just going to push a change to the release notes and then will merge. |
Fix: Don't break TOC when OpenAPI description includes headers
As noted in 0, the ability to render a CommonMark document through
OpenAPI specifications'
info.description
is breaking due to how theTable of Contents code works.
We'd assumed that the
id
would always be set on headers - by Middlemanwon't always have one.
Until the
openapi3_parser
gem supports making this configurable, whichis unlikely, due to the way that CommonMark doesn't have this as a
default extension, we can instead utilise our
TechDocsHTMLRenderer
torender the headings with IDs, as expected.
To do this, we can create a new helper in
ApiReferenceRenderer
whichwill render the Markdown document as our custom Markdown, which requires
we construct the
TechDocsHTMLRenderer
class, which needs the MiddlemanConfigContext
class injected in.This means that we won't be using CommonMark, as per the OpenAPI spec,
and this is something we'll look to address in #282.
Example rendering: