$template, 'html' => <<addExtension(new MarkdownExtension()); $twig->addRuntimeLoader(new class($class) implements RuntimeLoaderInterface { private $class; public function __construct(string $class) { $this->class = $class; } public function load(string $c): ?object { return MarkdownRuntime::class === $c ? new $c(new $this->class()) : null; } }); $this->assertMatchesRegularExpression('{'.$expected.'}m', trim($twig->render('index'))); } } public static function getMarkdownTests() { return [ [<<]*>Hello\n+

Great!\s*

"], [<<]*>Hello\n+

Great!\s*

"], ["{{ include('html')|markdown_to_html }}", "]*>Hello\n+

Great!\s*

"], [<<Paragraph 1

\n+

Paragraph 2\s*

"], ]; } #[DataProvider('getIndentationTests')] public function testStripsCommonIndentation(string $body, string $expected): void { $runtime = new MarkdownRuntime(new class implements MarkdownInterface { public function convert(string $body): string { return $body; } }); $this->assertSame($expected, $runtime->convert($body)); } public static function getIndentationTests() { return [ 'leading blank line keeps blank lines' => ["\nParagraph 1\n\nParagraph 2", "\nParagraph 1\n\nParagraph 2"], 'common indentation is removed' => ["\n Hello\n =====\n\n Great!\n", "\nHello\n=====\n\nGreat!\n"], 'minimal common indentation is removed' => [" a\n b\n", "a\n b\n"], 'indented code block before non-indented prose is preserved' => [" Code\n\nParagraph\n", " Code\n\nParagraph\n"], 'tab indentation is removed' => ["\tHello\n\tGreat!\n", "Hello\nGreat!\n"], 'mixed tabs and spaces are left untouched' => ["\ta\n b\n", "\ta\n b\n"], 'blank lines are ignored when computing indentation' => [" a\n\n b\n", "a\n\nb\n"], ]; } public function testMarkdownToHtmlIsNotSafeInJsContext(): void { $twig = new Environment(new ArrayLoader([ 'index' => "{% autoescape 'js' %}{{ '# Hello'|markdown_to_html }}{% endautoescape %}", ])); $twig->addExtension(new MarkdownExtension()); $twig->addRuntimeLoader(new class implements RuntimeLoaderInterface { public function load(string $c): ?object { return MarkdownRuntime::class === $c ? new $c(new DefaultMarkdown()) : null; } }); $output = $twig->render('index'); $this->assertStringNotContainsString('

', $output); $this->assertMatchesRegularExpression('{\\\\u003[Cc]h1\\\\u003[Ee]Hello\\\\u003[Cc]\\\\/h1\\\\u003[Ee]}', $output); } }