Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions packages/repl-sdk/src/compilers/markdown/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,14 @@ function unescapeComponentsOutsideCode(html) {
if (j % 2 === 0 && segment) {
codeParts[j] = segment
.replace(/&#x3C;([A-Z][a-zA-Z0-9]*\s[^<]*?)>/g, (_m, content) =>
content.includes('@') ? `<${content}>` : _m
content.includes('@') || content.includes('as |') ? `<${content}>` : _m
)
.replace(/&#x3C;\/([A-Z][a-zA-Z0-9]*)>/g, '</$1>');
.replace(/&#x3C;\/([A-Z][a-zA-Z0-9]*)>/g, '</$1>')
// When a block-param component tag (<Foo as |x|>) appears in
// inline markdown, the parser wraps it in <p>...</p>. Strip
// those spurious paragraph wrappers so Glimmer can parse the
// template without a tag-nesting mismatch.
.replace(/<p>(<[A-Z][^>]*as \|[^>]*>)<\/p>/g, '$1');
}
}

Expand Down
13 changes: 13 additions & 0 deletions packages/repl-sdk/src/compilers/markdown/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,19 @@ describe('default features', () => {
`);
});

it('allows component with block params (as |...|) invocation', async () => {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot add another test with more lines like the original issue report -- something still isn't working (still have the mismatched p tag error)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the more realistic test in d32b42b. The root issue was that when <Tabs as |Tab|> and <Tab @title="First"> appear on consecutive lines (no blank line between them), the markdown parser puts both into the SAME <p> block: <p><Tabs as |Tab|>\n<Tab @title="First"></p>. The previous regex only handled the case where the <p> contained only the opening block-param tag.

Fixed by switching to a tempered greedy token (?:(?!</p>)[\s\S])* that correctly matches content within a single <p> without crossing into adjacent paragraphs. The new test covers the realistic case from the issue report (h1 + text + <Tabs as |Tab|> with nested <Tab> components).

const result = await parseMarkdown([`<Tabs as |Tab|>`, ``, `info`, ``, `</Tabs>`].join('\n'), {
...defaults,
});

expect(result.codeBlocks).toMatchInlineSnapshot(`[]`);
expect(result.text).toMatchInlineSnapshot(`
"<Tabs as |Tab|>
<p>info</p>
</Tabs>"
`);
});

it('allows components to wrap markdown content', async () => {
const result = await parseMarkdown(
[
Expand Down