-
-
Notifications
You must be signed in to change notification settings - Fork 43
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
Improve handling of tight lists #23
Conversation
…item handler Since otherwise, we don't correctly handle tight lists containing multiple children, as in the case of - item one - item two
@wooorm could I get your thoughts on the relative merits of the fix proposed here vs the possible fix for the same problem at the layer of the parser? |
@Hamms Interesting! I’m just now rewriting the mdast spec, and am finding that tight / loose on lists and on items are pretty messy. They’re idea is that they’re useful for HTML, mostly, but as we’re not really using it here, that’s just weird! I saw that commonmark does not render the I think that the loose / tight problem should be fixed in remark-parse. These are just half thoughts, what do based on my ideas? |
Yeah, I wasn't sure how to feel about whether the problem should be fixed at the level of "paragraph" nodes or "p" tags; seems like it comes down to the question of whether "paragraph" nodes have some use beyond just being blindly converted into "p" tags. Fixing the problem here in the converter is saying that yes they do, and the handler (in this case, mdast-util-to-hast) should also be smart enough to know what tight lists are and know when they should and should not generate "p" tags. Fixing it in remark-parse would be saying that no they do not; they just exist to be turned into "p" tags and so the parser should be smart enough to know when to and to know inject them into the tree. I actually originally fixed this at the parser the layer, mostly because I didn't feel that I had a good sense for the role of the paragraph node in the greater remark ecosystem, and because the existing implementation puts that responsibility on mdast-util-to-hast and not on remark-parse, so I just went with the current direction. But if you're down with the idea of me changing things on a deeper level, I do I think prefer the "stupid" paragraph nodes philosophy. |
Upon further investigation, it looks like this solution actually introduces a problem with loose lists, because in the case of - item one
- item two remark-parse actually does not recognize the second item as being loose:
|
Given that any list item being loose should make the whole list behave as loose - which is a "going backwards" approach that seems pretty inconsistent with remark-parse's entire premise - it seems like this fix will require changes to both the parse and transform stages. First, parse should be updated to consistently create "paragraph" tags while still bubbling the |
@Hamms Maybe, but it’s based on commonmark! I dunno, I’m not sure of a better approach? |
I think it's possible to keep the approach consistent, it just requires embracing the idea of paragraph nodes as being something more semantically significant than just placeholders for p tags |
I agree with that idea, it’s what we’re doing now, and it works for me. |
…conditionally remove generated paragraph tags
…ms, and restore other subtle functionalities
@wooorm Please take another look! I believe I have the ultimate functionality where we want it to be; all the various ways of combining looseness, tightness, and nesting work as I expect them to. However, I'm not sure how I feel about the actual approach; rendering the results then modifying them like I'm doing feels inconsistent with the way subtrees are handled everywhere else in the codebase, but I'm not sure of a better way to do it. I'd love to hear your thoughts! Thanks! |
@wooorm Could you take a look at this when you get a chance? |
Hey, sorry for the slow response! I thought about it some more, see remarkjs/remark#364 for my current thinking. I think we can use the code here as a base on those changes in remark quite easily. |
Very exciting! I'll take a look as soon as I can |
* remark-parse: remove `loose` fields from `list`, `listItem` * remark-parse: add support for empty list-items in any non-pedantic mode * remark-parse: add `spread` to `list`, to signal that its items should have blank lines between them, set to true if any blank line exists between items * remark-parse: add `spread` to `listItem`, to signal that its children should have blank lines between them * remark-parse: fix bug where two lists, if they are both ordered or both not ordered, was seen in commonmark as one list * remark-stringify: add support for missing `ordered` field * remark-stringify: add support for missing `start` field * remark-stringify: add support for `list.spread` (default: false) * remark-stringify: add support for `listItem.spread` (default: true) * remark-stringify: fix bug where two lists, if they are both ordered or both not ordered, and in commonmark, were not properly stringified, resulting in a new parse seeing them as one list * remark-stringify: fix bug where a list followed by an indented code block, in commonmark, was not correctly stringified, resulting in a new parse seeing the code as content of the list * remark-stringify: remove trailing white-space on empty list-items * remark-stringify: add support for stringifying list-items without parent Related to syntax-tree/mdast#4. Related to syntax-tree/mdast-util-to-hast#23. Related to GH-349. Closes GH-332. Closes GH-350. Closes GH-358. Closes GH-364. Reviewed-by: Elijah Hamovitz <elijahhamovitz@gmail.com> Reviewed-by: Ika <ikatyang@gmail.com>
Context
In markdown, "tight" lists are supposed to render text without paragraph tags:
becomes:
In remark, this usually works, but it works in kind of a weird way. The original text is actually parsed to an MDAST tree that contains paragraph nodes:
And those tags are then removed by
mdast-util-to-hast
:mdast-util-to-hast/lib/handlers/list-item.js
Lines 18 to 24 in 1f8591e
The Problem
This usually results in correct HTML output, even though it's a bit weird to have "paragraph" nodes that don't then become "p" tags. However! This only works if the tight list item has a single child, which means that in cases like
we would expect to render to
but instead get
Because the node in the intermediate MDAST doesn't have just a single child:
The Solution
There are a couple of potential solutions here; one of them would be to avoid creating those unnecessary "paragraph" nodes in the first place, but another is toupgrade
mdast-util-to-hast
to be able to deal with this case as well. This latter solution is outlined in this PR.I still need to fix the tests that are affected by this change and write new ones for this new functionality, but before I invest that time I want to get your thoughts on the validity of pursuing this fix as opposed to the other one.