diff --git a/packages/svelte-markdown-preprocess/src/index.spec.ts b/packages/svelte-markdown-preprocess/src/index.spec.ts index bb9ca7f4..df049a92 100644 --- a/packages/svelte-markdown-preprocess/src/index.spec.ts +++ b/packages/svelte-markdown-preprocess/src/index.spec.ts @@ -98,6 +98,49 @@ describe(svelteMarkdownPreprocess.name, () => { }); }); + describe('svelte components', () => { + const render = async (content: string) => { + const result = await svelteMarkdownPreprocess().markup({ filename: 'test.md', content }); + return result?.code ?? ''; + }; + + it('should render a component that owns its line', async () => { + await expect(render('')).resolves.toContain(''); + }); + + it('should render sibling components sharing a line', async () => { + const code = await render(' '); + + expect(code).toContain(''); + expect(code).toContain(''); + expect(code).not.toContain('<'); + }); + + it('should render a component followed by prose on the same line', async () => { + const code = await render('In order to use this'); + + expect(code).toContain(''); + expect(code).toContain('In order to use this'); + }); + + it('should render a component preceded by prose on the same line', async () => { + await expect(render('Look at this ')).resolves.toContain( + 'Look at this ', + ); + }); + + it('should import a relative source from a component sharing a line', async () => { + const code = await render('Look at this '); + + expect(code).toContain(`import __image_0 from './img/example.webp';`); + expect(code).toContain(''); + }); + + it('should leave a component inside a code fence as code', async () => { + await expect(render('```svelte\n\n```')).resolves.toContain(' { it('should import relative images so vite can optimize them', async () => { const result = await svelteMarkdownPreprocess().markup({ diff --git a/packages/svelte-markdown-preprocess/src/markdown.ts b/packages/svelte-markdown-preprocess/src/markdown.ts index 1ed1791f..2c1b7072 100644 --- a/packages/svelte-markdown-preprocess/src/markdown.ts +++ b/packages/svelte-markdown-preprocess/src/markdown.ts @@ -27,7 +27,8 @@ const renderAlert = ( ) => `${parser.parse(tokens)}\n`; // Marked reads a dotted tag as text, so a component like `` needs its own rule. -const SVELTE_COMPONENT_REGEX = /^<[A-Z]\w*\.\w+\b[^>]*\/>[ \t]*(?:\n+|$)/; +const SVELTE_COMPONENT_REGEX = /^<[A-Z]\w*\.\w+\b[^>]*\/>/; +const SVELTE_COMPONENT_BLOCK_REGEX = new RegExp(String.raw`${SVELTE_COMPONENT_REGEX.source}[ \t]*\n?`); const normalizeText = (text: string) => escapeHtml(emojify(text)); @@ -75,9 +76,16 @@ export const markedSvelte = (): MarkedExtension => ({ }, html(src) { - const match = SVELTE_COMPONENT_REGEX.exec(src); + const match = SVELTE_COMPONENT_BLOCK_REGEX.exec(src); return match ? { type: 'html', raw: match[0], text: `${match[0].trim()}\n`, pre: false, block: true } : false; }, + + tag(src) { + const match = SVELTE_COMPONENT_REGEX.exec(src); + return match + ? { type: 'html', raw: match[0], text: match[0], inLink: false, inRawBlock: false, block: false } + : false; + }, }, extensions: [