diff --git a/package.json b/package.json index 149aadf..5fa26c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "markdown-converter", - "version": "4.4.1", + "version": "4.4.2", "description": "Professional Markdown editor and universal file converter with PDF editing, batch processing, and syntax highlighting", "main": "src/main.js", "scripts": { diff --git a/src/index.html b/src/index.html index 2e8620b..c79af69 100644 --- a/src/index.html +++ b/src/index.html @@ -288,6 +288,52 @@ +
Select a PDF to view pages, check to delete, click ↻ to rotate, and use ◀ / ▶ to reorder.
+Be careful!
') + }; + const context = { parser: mockParser }; + const html = extension.renderer.call(context, token); + + expect(html).toContain('admonition admonition-warning'); + expect(html).toContain('⚠ Warning'); + expect(html).toContain('Be careful!
'); + expect(mockParser.parse).toHaveBeenCalledWith(token.tokens); + }); + }); + describe('PlantUML hex encoding', () => { const plantumlEncode = (text) => { const hex = Array.from(Buffer.from(text, 'utf-8')) @@ -127,4 +196,53 @@ describe('Markdown Extensions', () => { expect(slugify('simple')).toBe('simple'); }); }); + + describe('scopeCSS utility', () => { + const scopeCSS = (cssText, scopeSelector) => { + if (!cssText) return ''; + return cssText.replace(/([^\r\n,{}]+)(,(?=[^}]*{)|(?=[^{]*{))/g, (match, selector, separator) => { + const trimmed = selector.trim(); + if (!trimmed || trimmed.startsWith('@') || trimmed.startsWith(':root') || trimmed.startsWith('from') || trimmed.startsWith('to') || /^\d+%$/.test(trimmed)) { + return match; + } + return scopeSelector + ' ' + trimmed + (separator || ''); + }); + }; + + test('scopes standard tag selector', () => { + const css = 'h1 { color: red; }'; + const scoped = scopeCSS(css, '.preview-content'); + expect(scoped).toBe('.preview-content h1{ color: red; }'); + }); + + test('scopes multiple class selectors', () => { + const css = '.title, .content { font-family: sans-serif; }'; + const scoped = scopeCSS(css, '.preview-content'); + expect(scoped).toBe('.preview-content .title,.preview-content .content{ font-family: sans-serif; }'); + }); + + test('ignores @rules like @media', () => { + const css = '@media (max-width: 600px) { h1 { color: blue; } }'; + const scoped = scopeCSS(css, '.preview-content'); + expect(scoped).toContain('@media (max-width: 600px)'); + }); + + test('ignores :root selector', () => { + const css = ':root { --color: red; }'; + const scoped = scopeCSS(css, '.preview-content'); + expect(scoped).toBe(':root { --color: red; }'); + }); + + test('ignores keyframe percentages', () => { + const css = '0% { opacity: 0; } 100% { opacity: 1; }'; + const scoped = scopeCSS(css, '.preview-content'); + expect(scoped).toContain('0%'); + expect(scoped).toContain('100%'); + }); + + test('handles empty input', () => { + expect(scopeCSS('', '.preview-content')).toBe(''); + expect(scopeCSS(null, '.preview-content')).toBe(''); + }); + }); });