fix: keep the form a reference definition was authored with - #376
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A reference definition is now written back in the form it was authored in. #260 kept the definition rather than inlining it and deleting it, but it was still written in the serializer's own form: angle brackets around the destination were dropped, and a title written on its own continuation line was folded onto the destination's line.
Three attributes carry what a definition's label, destination, title, and title marker did not already answer for: the form the destination was written in, and the two whitespace runs CommonMark lets a definition spend a line ending in.
leafdownReferenceLinkstamps all three onto the mdast definition beside the title marker it already stamped, read off the slice the node was built from, and thedefinitionnode carries them as attributes.serializeMarkdownDefinitionwrites the line itself rather than steeringdefaultHandlers.definition. That handler makes four choices — the label, the destination's form, the title's marker, and the whitespace between them — and the document now owns three of them. What is left is escaping, which every run still reaches the file through, under the construct name the default handler enters for it, so what a destination or a title gives up a backslash for is unchanged. Writing the title's marker directly also retires thetrailingparameterwithAuthoredTitlecarried for definitions alone, which existed only to locate that marker in the default handler's output.The recorded runs are read past the columns the definition's container owns, named by the definition's own starting column. A container writes its prefix back around every line the serializer makes, so a run recorded through that prefix is added to it: a definition in a list item whose title stands on the next line would gain the item's indentation on the first save and gain it again on the next. Reading past the prefix instead leaves the blockquote, nested blockquote, and list item forms byte-identical, and leaves a prefix the column count does not describe unreadable, which is the default one-line form rather than a guess.
The recorded form only ever adds the brackets. A destination that cannot be read back bare — an empty one, and one holding whitespace or a control character — is written between them whatever the file recorded, which a bare destination reaches through a character reference the parse decodes into it.
.leafdown-definitionrenders withwhite-space: pre-wrap, because the block shows the source the file is written with and that source can now hold a line ending and the indentation under it.Related Issue
Closes #325
Verification
markdownCompatibility.test.tsgains aDefinition formgroup.Twenty rows assert the written bytes and the reopened document together, because a destination written in a form the next read does not answer for costs the destination rather than the form. They cover both destination forms, a destination the bare form cannot spell and one it could, both brackets escaped inside an angle destination, a colon followed by no whitespace at all, a title separated by a space, by a tab, and by three spaces, a title and a destination each on a line of their own, both runs spending their line ending at once, and the same layouts inside a blockquote, a nested blockquote, and a list item.
Three more tests cover the bracket a recorded form cannot withhold, a two-line definition rendered as both of its lines, and a layout read past a prefix another class moves — a lazy continuation and a blockquote marker written without its space — each asserted across a second save.
corpusRoundTrip.test.tsis unchanged and still passes.corpus/commonmark/blocks.mdloses both differences this issue names, measured by saving the file once and comparing it to itself, which is the fourthDone whenitem.Not verified: the application was not run. The rendered block's text content is asserted, so what rests on the stylesheet alone is that
pre-wrapshows the line ending and indentation that text content already holds.Notes
corpus/commonmark/blocks.mdstays on the convergence assertion. Its definition sections are left holding only the blank line the serializer inserts between two adjacent definitions, which this issue puts out of scope as the blank-line class, and the file is held short of identity by that class and by the escape classes The serializer escapes a marker run too short to open a thematic break #373, The serializer escapes a backtick that cannot form a code span where it sits #374, and The serializer escapes a hyphen run that cannot open a block where it sits #375 besides.[a]: <b&c.md>is written[a]: <b&c.md>. That belongs to A character reference is decoded and saved as the literal character #262, whoseauthoredUrlrecording reaches links and images rather than definitions, and it is untouched here.<and>inside an angle destination, which it did not before. It shows the source the file is written with, and the file has always escaped both there; the two disagreed only for a destination spelling one of them, which this branch makes reachable for any destination rather than only for one that needs the brackets.