diff --git a/bin/auto-sync.txt b/bin/auto-sync.txt
index ba848805..9094e760 100644
--- a/bin/auto-sync.txt
+++ b/bin/auto-sync.txt
@@ -45,6 +45,7 @@ line-up
linked-list
list-ops
luhn
+markdown
matching-brackets
meetup
micro-blog
diff --git a/exercises/practice/markdown/.docs/instructions.md b/exercises/practice/markdown/.docs/instructions.md
index 4819b6c2..b3f3044c 100644
--- a/exercises/practice/markdown/.docs/instructions.md
+++ b/exercises/practice/markdown/.docs/instructions.md
@@ -2,14 +2,12 @@
Refactor a Markdown parser.
-The markdown exercise is a refactoring exercise. There is code that parses a
-given string with [Markdown
-syntax](https://guides.github.com/features/mastering-markdown/) and returns the
-associated HTML for that string. Even though this code is confusingly written
-and hard to follow, somehow it works and all the tests are passing! Your
-challenge is to re-write this code to make it easier to read and maintain
-while still making sure that all the tests keep passing.
-
-It would be helpful if you made notes of what you did in your refactoring in
-comments so reviewers can see that, but it isn't strictly necessary. The most
-important thing is to make the code better!
+The markdown exercise is a refactoring exercise.
+There is code that parses a given string with [Markdown syntax][markdown] and returns the associated HTML for that string.
+Even though this code is confusingly written and hard to follow, somehow it works and all the tests are passing!
+Your challenge is to re-write this code to make it easier to read and maintain while still making sure that all the tests keep passing.
+
+It would be helpful if you made notes of what you did in your refactoring in comments so reviewers can see that, but it isn't strictly necessary.
+The most important thing is to make the code better!
+
+[markdown]: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
diff --git a/exercises/practice/markdown/.meta/config.json b/exercises/practice/markdown/.meta/config.json
index 294e9344..460acbed 100644
--- a/exercises/practice/markdown/.meta/config.json
+++ b/exercises/practice/markdown/.meta/config.json
@@ -5,7 +5,8 @@
"contributors": [
"arueckauer",
"kytrinyx",
- "yisraeldov"
+ "yisraeldov",
+ "Narkunan"
],
"files": {
"solution": [
@@ -18,5 +19,5 @@
".meta/example.php"
]
},
- "blurb": "Refactor a Markdown parser"
+ "blurb": "Refactor a Markdown parser."
}
diff --git a/exercises/practice/markdown/.meta/example.php b/exercises/practice/markdown/.meta/example.php
index 5f3a447c..8f4a439b 100644
--- a/exercises/practice/markdown/.meta/example.php
+++ b/exercises/practice/markdown/.meta/example.php
@@ -31,51 +31,64 @@ function parseMarkdown($markdown)
$isInList = false;
foreach ($lines as &$line) {
- if (preg_match('/^######(.*)/', $line, $matches)) {
+ if (preg_match('/^####### (.*)/', $line, $matches)) {
+ $line = "
" . trim($matches[0]) . "
";
+ } elseif (preg_match('/^###### (.*)/', $line, $matches)) {
$line = "" . trim($matches[1]) . "
";
- } elseif (preg_match('/^##(.*)/', $line, $matches)) {
+ } elseif (preg_match('/^##### (.*)/', $line, $matches)) {
+ $line = "" . trim($matches[1]) . "
";
+ } elseif (preg_match('/^#### (.*)/', $line, $matches)) {
+ $line = "" . trim($matches[1]) . "
";
+ } elseif (preg_match('/^### (.*)/', $line, $matches)) {
+ $line = "" . trim($matches[1]) . "
";
+ } elseif (preg_match('/^## (.*)/', $line, $matches)) {
$line = "" . trim($matches[1]) . "
";
- } elseif (preg_match('/^#(.*)/', $line, $matches)) {
+ } elseif (preg_match('/^# (.*)/', $line, $matches)) {
$line = "" . trim($matches[1]) . "
";
}
- if (preg_match('/\*(.*)/', $line, $matches)) {
+ if (preg_match('/^\s*\*(.*)/', $line, $matches)) {
if (!$isInList) {
$isInList = true;
$isBold = false;
$isItalic = false;
if (preg_match('/(.*)__(.*)__(.*)/', $matches[1], $matches2)) {
- $matches[1] = $matches2[1] . '' . $matches2[2] . '' . $matches2[3];
+ $matches[1] = $matches2[1] . '' . $matches2[2] . '' . $matches2[3];
$isBold = true;
}
if (preg_match('/(.*)_(.*)_(.*)/', $matches[1], $matches3)) {
- $matches[1] = $matches3[1] . '' . $matches3[2] . '' . $matches3[3];
+ $matches[1] = $matches3[1] . '' . $matches3[2] . '' . $matches3[3];
$isItalic = true;
}
if ($isItalic || $isBold) {
$line = "- " . trim($matches[1]) . "
";
} else {
- $line = "" . trim($matches[1]) . "
";
+ $line = "" . trim($matches[1]) . "
";
+ } else {
+ $line = "$line
";
+ }
}
if (preg_match('/(.*)__(.*)__(.*)/', $line, $matches)) {
- $line = $matches[1] . '' . $matches[2] . '' . $matches[3];
+ $line = $matches[1] . '' . $matches[2] . '' . $matches[3];
}
if (preg_match('/(.*)_(.*)_(.*)/', $line, $matches)) {
- $line = $matches[1] . '' . $matches[2] . '' . $matches[3];
+ $line = $matches[1] . '' . $matches[2] . '' . $matches[3];
}
}
-
$html = join($lines);
-
if ($isInList) {
$html .= '
';
}
-
return $html;
}
diff --git a/exercises/practice/markdown/.meta/tests.toml b/exercises/practice/markdown/.meta/tests.toml
index fecbcf50..28b7baa7 100644
--- a/exercises/practice/markdown/.meta/tests.toml
+++ b/exercises/practice/markdown/.meta/tests.toml
@@ -1,6 +1,13 @@
-# This is an auto-generated file. Regular comments will be removed when this
-# file is regenerated. Regenerating will not touch any manually added keys,
-# so comments can be added in a "comment" key.
+# This is an auto-generated file.
+#
+# Regenerating this file via `configlet sync` will:
+# - Recreate every `description` key/value pair
+# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
+# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
+# - Preserve any other key/value pair
+#
+# As user-added comments (using the # character) will be removed when this file
+# is regenerated, comments can be added via a `comment` key.
[e75c8103-a6b8-45d9-84ad-e68520545f6e]
description = "parses normal text as a paragraph"
@@ -20,9 +27,26 @@ description = "with h1 header level"
[d0f7a31f-6935-44ac-8a9a-1e8ab16af77f]
description = "with h2 header level"
+[9df3f500-0622-4696-81a7-d5babd9b5f49]
+description = "with h3 header level"
+
+[50862777-a5e8-42e9-a3b8-4ba6fcd0ed03]
+description = "with h4 header level"
+
+[ee1c23ac-4c86-4f2a-8b9c-403548d4ab82]
+description = "with h5 header level"
+
[13b5f410-33f5-44f0-a6a7-cfd4ab74b5d5]
description = "with h6 header level"
+[6dca5d10-5c22-4e2a-ac2b-bd6f21e61939]
+description = "with h7 header level"
+include = false
+
+[81c0c4db-435e-4d77-860d-45afacdad810]
+description = "h7 header level is a paragraph"
+reimplements = "6dca5d10-5c22-4e2a-ac2b-bd6f21e61939"
+
[25288a2b-8edc-45db-84cf-0b6c6ee034d6]
description = "unordered lists"
diff --git a/exercises/practice/markdown/Markdown.php b/exercises/practice/markdown/Markdown.php
index 961d8914..8f4a439b 100644
--- a/exercises/practice/markdown/Markdown.php
+++ b/exercises/practice/markdown/Markdown.php
@@ -31,51 +31,64 @@ function parseMarkdown($markdown)
$isInList = false;
foreach ($lines as &$line) {
- if (preg_match('/^######(.*)/', $line, $matches)) {
+ if (preg_match('/^####### (.*)/', $line, $matches)) {
+ $line = "" . trim($matches[0]) . "
";
+ } elseif (preg_match('/^###### (.*)/', $line, $matches)) {
$line = "" . trim($matches[1]) . "
";
- } elseif (preg_match('/^##(.*)/', $line, $matches)) {
+ } elseif (preg_match('/^##### (.*)/', $line, $matches)) {
+ $line = "" . trim($matches[1]) . "
";
+ } elseif (preg_match('/^#### (.*)/', $line, $matches)) {
+ $line = "" . trim($matches[1]) . "
";
+ } elseif (preg_match('/^### (.*)/', $line, $matches)) {
+ $line = "" . trim($matches[1]) . "
";
+ } elseif (preg_match('/^## (.*)/', $line, $matches)) {
$line = "" . trim($matches[1]) . "
";
- } elseif (preg_match('/^#(.*)/', $line, $matches)) {
+ } elseif (preg_match('/^# (.*)/', $line, $matches)) {
$line = "" . trim($matches[1]) . "
";
}
- if (preg_match('/\*(.*)/', $line, $matches)) {
+ if (preg_match('/^\s*\*(.*)/', $line, $matches)) {
if (!$isInList) {
$isInList = true;
$isBold = false;
$isItalic = false;
if (preg_match('/(.*)__(.*)__(.*)/', $matches[1], $matches2)) {
- $matches[1] = $matches2[1] . '' . $matches2[2] . '' . $matches2[3];
+ $matches[1] = $matches2[1] . '' . $matches2[2] . '' . $matches2[3];
$isBold = true;
}
if (preg_match('/(.*)_(.*)_(.*)/', $matches[1], $matches3)) {
- $matches[1] = $matches3[1] . '' . $matches3[2] . '' . $matches3[3];
+ $matches[1] = $matches3[1] . '' . $matches3[2] . '' . $matches3[3];
$isItalic = true;
}
if ($isItalic || $isBold) {
$line = "- " . trim($matches[1]) . "
";
} else {
- $line = "" . trim($matches[1]) . "
";
+ $line = "" . trim($matches[1]) . "
";
+ } else {
+ $line = "$line
";
+ }
}
if (preg_match('/(.*)__(.*)__(.*)/', $line, $matches)) {
- $line = $matches[1] . '' . $matches[2] . '' . $matches[3];
+ $line = $matches[1] . '' . $matches[2] . '' . $matches[3];
}
if (preg_match('/(.*)_(.*)_(.*)/', $line, $matches)) {
- $line = $matches[1] . '' . $matches[2] . '' . $matches[3];
+ $line = $matches[1] . '' . $matches[2] . '' . $matches[3];
}
}
$html = join($lines);
diff --git a/exercises/practice/markdown/MarkdownTest.php b/exercises/practice/markdown/MarkdownTest.php
index 9e2c7bf5..43289825 100644
--- a/exercises/practice/markdown/MarkdownTest.php
+++ b/exercises/practice/markdown/MarkdownTest.php
@@ -24,6 +24,7 @@
declare(strict_types=1);
+use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;
class MarkdownTest extends TestCase
@@ -33,54 +34,172 @@ public static function setUpBeforeClass(): void
require_once 'Markdown.php';
}
+ /** uuid: e75c8103-a6b8-45d9-84ad-e68520545f6e */
+ #[TestDox('parses normal text as a paragraph')]
public function testParsingParagraph(): void
{
- $this->assertEquals('This will be a paragraph
', parseMarkdown('This will be a paragraph'));
+ $this->assertEquals(
+ "This will be a paragraph
",
+ parseMarkdown("This will be a paragraph")
+ );
}
+ /** uuid: 69a4165d-9bf8-4dd7-bfdc-536eaca80a6a */
+ #[TestDox('parsing italics')]
public function testParsingItalics(): void
{
- $this->assertEquals('This will be italic
', parseMarkdown('_This will be italic_'));
+ $this->assertEquals(
+ "This will be italic
",
+ parseMarkdown("_This will be italic_")
+ );
}
+ /** uuid: ec345a1d-db20-4569-a81a-172fe0cad8a1 */
+ #[TestDox('parsing bold text')]
public function testParsingBoldText(): void
{
- $this->assertEquals('This will be bold
', parseMarkdown('__This will be bold__'));
+ $this->assertEquals(
+ "This will be bold
",
+ parseMarkdown("__This will be bold__")
+ );
}
+ /** uuid: 51164ed4-5641-4909-8fab-fbaa9d37d5a8 */
+ #[TestDox('mixed normal, italics and bold text')]
public function testMixedNormalItalicsAndBoldText(): void
{
- $this->assertEquals('This will be mixed
', parseMarkdown('This will _be_ __mixed__'));
+ $this->assertEquals(
+ "This will be mixed
",
+ parseMarkdown("This will _be_ __mixed__")
+ );
}
+ /** uuid: ad85f60d-0edd-4c6a-a9b1-73e1c4790d15 */
+ #[TestDox('with h1 header level')]
public function testWithH1Headerlevel(): void
{
- $this->assertEquals('This will be an h1
', parseMarkdown('# This will be an h1'));
+ $this->assertEquals(
+ "This will be an h1
",
+ parseMarkdown("# This will be an h1")
+ );
}
+ /** uuid: d0f7a31f-6935-44ac-8a9a-1e8ab16af77f */
+ #[TestDox('with h2 header level')]
public function testWithH2Headerlevel(): void
{
- $this->assertEquals('This will be an h2
', parseMarkdown('## This will be an h2'));
+ $this->assertEquals(
+ "This will be an h2
",
+ parseMarkdown("## This will be an h2")
+ );
+ }
+
+ /** uuid: 9df3f500-0622-4696-81a7-d5babd9b5f49 */
+ #[TestDox('with h3 header level')]
+ public function testWithH3headerLevel(): void
+ {
+ $this->assertEquals(
+ "This will be an h3
",
+ parseMarkdown("### This will be an h3")
+ );
+ }
+
+ /** uuid: 50862777-a5e8-42e9-a3b8-4ba6fcd0ed03 */
+ #[TestDox('with h4 header level')]
+ public function testWithH4headerLevel(): void
+ {
+ $this->assertEquals(
+ "This will be an h4
",
+ parseMarkdown("#### This will be an h4")
+ );
+ }
+
+ /** uuid: ee1c23ac-4c86-4f2a-8b9c-403548d4ab82 */
+ #[TestDox('with h5 header level')]
+ public function testWithH5headerLevel(): void
+ {
+ $this->assertEquals(
+ "This will be an h5
",
+ parseMarkdown("##### This will be an h5")
+ );
}
+ /** uuid: 13b5f410-33f5-44f0-a6a7-cfd4ab74b5d5 */
+ #[TestDox('with h6 header level')]
public function testWithH6Headerlevel(): void
{
- $this->assertEquals('This will be an h6
', parseMarkdown('###### This will be an h6'));
+ $this->assertEquals(
+ "This will be an h6
",
+ parseMarkdown("###### This will be an h6")
+ );
}
+ /** uuid: 81c0c4db-435e-4d77-860d-45afacdad810 */
+ #[TestDox('h7 header level is a paragraph')]
+ public function testH7HeaderIsAParagraph(): void
+ {
+ $this->assertEquals(
+ "####### This will not be an h7
",
+ parseMarkdown("####### This will not be an h7")
+ );
+ }
+
+ /** uuid: 25288a2b-8edc-45db-84cf-0b6c6ee034d6 */
+ #[TestDox('unordered lists')]
public function testUnorderedLists(): void
{
$this->assertEquals(
- '',
+ "",
parseMarkdown("* Item 1\n* Item 2")
);
}
+ /** uuid: 7bf92413-df8f-4de8-9184-b724f363c3da */
+ #[TestDox('With a little bit of everything')]
public function testWithALittleBitOfEverything(): void
{
$this->assertEquals(
- 'Header!
',
+ "Header!
",
parseMarkdown("# Header!\n* __Bold Item__\n* _Italic Item_")
);
}
+
+ /** uuid: 0b3ed1ec-3991-4b8b-8518-5cb73d4a64fe */
+ #[TestDox('with markdown symbols in the header text that should not be interpreted')]
+ public function testMarkdownSymbolInHeaderText(): void
+ {
+ $this->assertEquals(
+ "This is a header with # and * in the text
",
+ parseMarkdown("# This is a header with # and * in the text")
+ );
+ }
+#
+ /** uuid: 113a2e58-78de-4efa-90e9-20972224d759 */
+ #[TestDox('with markdown symbols in the list item text that should not be interpreted')]
+ public function testMarkdownSymbolInListItemText(): void
+ {
+ $this->assertEquals(
+ "- Item 1 with a # in the text
- Item 2 with * in the text
",
+ parseMarkdown("* Item 1 with a # in the text\n* Item 2 with * in the text")
+ );
+ }
+ /** uuid: e65e46e2-17b7-4216-b3ac-f44a1b9bcdb4 */
+ #[TestDox('with markdown symbols in the paragraph text that should not be interpreted')]
+ public function testMarkdownSymbolInParagraph(): void
+ {
+ $this->assertEquals(
+ "This is a paragraph with # and * in the text
",
+ parseMarkdown("This is a paragraph with # and * in the text")
+ );
+ }
+
+ /** uuid: f0bbbbde-0f52-4c0c-99ec-be4c60126dd4 */
+ #[TestDox('unordered lists close properly with preceding and following lines')]
+ public function testUnorderedListCloseProperlyWithPrecedingAndFollowingLines(): void
+ {
+ $this->assertEquals(
+ "Start a list
End a list
",
+ parseMarkdown("# Start a list\n* Item 1\n* Item 2\nEnd a list")
+ );
+ }
}