fix(inline-props): apply end-of-line attributes to block tokens when inline Markdown present#16
fix(inline-props): apply end-of-line attributes to block tokens when inline Markdown present#16kentrpg wants to merge 5 commits intocomarkdown:mainfrom
Conversation
…inline Markdown present
| <p><code style="color: red">code</code></p> | ||
| <p><em style="color: blue">italic</em></p> | ||
| <p style="color: red"><code>code</code></p> | ||
| <p style="color: blue"><em>italic</em></p> |
There was a problem hiding this comment.
I am not so sure about this behaviour change, shouldn't the style applied to the code and em tag?
There was a problem hiding this comment.
Sorry about that! I was testing another (not yet submitted) issue and PR related to inline-props, and accidentally included those output changes in this PR’s tests.
I noticed the mistake and have already reverted the unintended output changes in this commit.
There was a problem hiding this comment.
Can you revert that and update the snapshot? Thanks
There was a problem hiding this comment.
I am not so sure about this behaviour change, shouldn't the style applied to the
codeandemtag?
Sorry, I was a bit nervous sending my first PR to a technical guru!
I've reviewed the logic again:
Since the attribute syntax is placed at the end of the line, the style is now applied to the block-level <p> tag, not the code or em tag.
`code`{style="color: red"}
_italic_{style="color: blue"}If the attribute syntax needs to apply to the inline-level token instead, I found that adding an empty {} at the end works without changing any other logic. What do you think about this approach?
For example:
`code`{style="color: red"}{}
_italic_{style="color: blue"}{}
[Link](https://nuxt.com){class="nuxt"}{}
{#nuxt-logo}{}
There was a problem hiding this comment.
Sorry, just to double-check, should I only revert test(fixtures): fix unintended changes in inline-props output this commit, or do I also need to update the snapshot after reverting? Thanks
There was a problem hiding this comment.
I personally think {class="nuxt"}{} is a bit counter intutive, as I would expect
foo **bar**{style="color: red"} baz
**bar**{style="color: red"}
to behave the same, that applying the style to the b element
There was a problem hiding this comment.
I’d like to ask for a bit more detail about your expectation.
Are you expecting this behavior only when the attribute syntax sets a style property?
If so, I think I can adjust the condition like this:
if (
token.type === 'inline' &&
token.children?.[token.children.length - 1].type === 'mdc_inline_props' &&
token.children[token.children.length - 1].attrs.length === 1 &&
token.children[token.children.length - 1].attrs[0][0] === 'style'
) {
// ...
}
The logic here is to check whether the last mdc_inline_props token only has a style attribute.
Other attributes can still be applied to the block-level token.for example, **bar**{.text-red} would apply the class to the p element.
There was a problem hiding this comment.
Apply attributes to the parent token only when the content is not purely inline elements.
Below is my attempt at designing the filtering logic with a reverse for loop.
if (token.type === "inline" && token.children?.[token.children.length - 1].type === "mdc_inline_props") {
const contentTokens = token.children.slice(0, -1)
let inlineCount = 0
let onlyInline = true
for (let index = contentTokens.length - 1; index >= 0; index--) {
if (contentTokens[index].type === 'text') {
if (!contentTokens[index].content.trim())
continue
onlyInline = false
break
}
// handle self-closing token
if (contentTokens[index].nesting === 0) {
inlineCount++
continue
}
let searchIndex = index - 1
while (searchIndex >= 0) {
const searchToken = contentTokens[searchIndex]
if (searchToken.nesting === 1
&& searchToken.tag === contentTokens[index].tag
&& searchToken.level === contentTokens[index].level
) {
break
}
searchIndex--
}
if (searchIndex < 0)
throw new Error(`No matching opening tag found for ${JSON.stringify(contentTokens[index])}`)
index = searchIndex
inlineCount++
}
if (!onlyInline || inlineCount !== 1) {
const props = token.children.pop()?.attrs
props?.forEach(([key, value]) => {
if (key === "class")
prev.attrJoin("class", value)
else
prev.attrSet(key, value)
})
}
}
Not sure if this meets your expectation.
Description
This PR fixes that end-of-line attributes are correctly applied to the parent block-level token, even when the line contains other inline Markdown syntax.
Before
Previously, attributes were incorrectly applied to the last inline element. For example, this Markdown:
would render as:
After
With this change, the same Markdown now produces the correct HTML, with the attributes applied to the parent
<p>tag:Linked Issues
fix #15
Additional context