From d6f45453254ea41acfbf6efb5655caac228799de Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Thu, 18 Aug 2022 16:31:21 +0200 Subject: [PATCH 1/8] added test for paragraph annotations --- tests/GenericBlocksTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/GenericBlocksTest.php b/tests/GenericBlocksTest.php index 43cd151..03114ba 100644 --- a/tests/GenericBlocksTest.php +++ b/tests/GenericBlocksTest.php @@ -44,4 +44,20 @@ this is a paragraph [$source, $result] = createTest($source, $target); $this->assertEquals($source, $result); } + + public function testParagraphAnnotations() : void { + $source = " + +this is an annotated paragraph {.classA, .classB} + + "; + $target = " +

+ this is an annotated paragraph {.classA, .classB} +

+ "; + + [$source, $result] = createTest($source, $target); + $this->assertEquals($source, $result); + } } \ No newline at end of file -- 2.20.1 From 499b2b6fe459855bbd9f17983cd566d6908471c2 Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Thu, 18 Aug 2022 16:55:36 +0200 Subject: [PATCH 2/8] fixed annotation test --- tests/GenericBlocksTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/GenericBlocksTest.php b/tests/GenericBlocksTest.php index 03114ba..57e673a 100644 --- a/tests/GenericBlocksTest.php +++ b/tests/GenericBlocksTest.php @@ -53,7 +53,7 @@ this is an annotated paragraph {.classA, .classB} "; $target = "

- this is an annotated paragraph {.classA, .classB} + this is an annotated paragraph

"; -- 2.20.1 From 6100cf0f6b2e63b1355c54f171853c300708919e Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Thu, 18 Aug 2022 16:56:07 +0200 Subject: [PATCH 3/8] added `LBRACE` and `RBRACE` tokens to lexer --- src/Lexer.php | 8 ++++++++ src/Token.php | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/Lexer.php b/src/Lexer.php index 00bf586..9a386fd 100644 --- a/src/Lexer.php +++ b/src/Lexer.php @@ -104,6 +104,14 @@ class Lexer { $clearBuffer(); array_push($tokens, new Token(TokenType::COLON, $char)); break; + case '{': + $clearBuffer(); + array_push($tokens, new Token(TokenType::LBRACE, $char)); + break; + case '}': + $clearBuffer(); + array_push($tokens, new Token(TokenType::RBRACE, $char)); + break; default: $buffer .= $char; break; diff --git a/src/Token.php b/src/Token.php index d3a4b78..a0cf6dc 100644 --- a/src/Token.php +++ b/src/Token.php @@ -22,6 +22,8 @@ enum TokenType { case PIPE ; case GT ; case TAB ; + case LBRACE ; + case RBRACE ; } class Token { -- 2.20.1 From 9d407c370605fa29bc77efd0db1dcc2da5b8a30e Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Thu, 18 Aug 2022 17:19:36 +0200 Subject: [PATCH 4/8] now parsing `id` and `class` annotations on paragraphs --- src/Parser.php | 53 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index 208db2e..ff48133 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -2,6 +2,7 @@ namespace parkdown; +use Attribute; use DOMDocument; use DOMElement; use DOMNode; @@ -11,6 +12,11 @@ enum ListType { case UNORDERED; } +class Attributes { + public array $classes = []; + public ?string $id = null; +} + class Parser { const MAGIC_CHAR = "*"; @@ -148,8 +154,8 @@ class Parser { } private function parseText($paragraph = false) : array { - $elms = []; - $buffer = ""; + $elms = []; + $buffer = ""; $clearBuffer = function() use (&$elms, &$buffer) { array_push($elms, $this->document->createTextNode($buffer)); @@ -228,6 +234,41 @@ class Parser { $clearBuffer(); array_push($elms, $elm); continue; + } elseif ($this->current()->type === TokenType::LBRACE) { + $lbrace = $this->consume(); + assert($lbrace->type === TokenType::LBRACE, "expected left brace, got ".$lbrace->type->name); + + $content = ""; + while ($this->current()->type !== TokenType::EOF && + $this->current()->type !== TokenType::EOL && + $this->current()->type !== TokenType::RBRACE) { + $content .= $this->consume()->data; + } + $rbrace = $this->consume(); + assert($rbrace->type === TokenType::RBRACE, "expected right brace, got ".$rbrace->type->name); + + $attributes = array_map(function($element) { + return trim($element); + }, explode(',', $content)); + + $obj = new Attributes(); + + foreach($attributes as $attribute) { + if (!in_array($attribute[0], [".", "#"])) + continue; + switch ($attribute[0]) { + case ".": + array_push($obj->classes, substr($attribute, 1)); + break; + case "#": + $obj->id = substr($attribute, 1); + break; + default: + continue 2; + } + } + + array_push($elms, $obj); } else $buffer .= self::StripBackslashes($this->consume()->data); } @@ -307,6 +348,14 @@ class Parser { $elm = $this->document->createElement("p"); $i = 0; foreach ($elms as $node) { + if ($node instanceof Attributes) { + if (count($node->classes) > 0) + $elm->setAttribute("class", join(" ", $node->classes)); + if ($node->id) + $elm->setAttribute("id", $node->id); + + continue; + } if ($node->nodeName === "#text" && trim($node->textContent) === "") continue; $elm->appendChild($node); -- 2.20.1 From b71dd1d440a1d56e159c453f9f3db431523ee77f Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Thu, 18 Aug 2022 17:41:30 +0200 Subject: [PATCH 5/8] added annotation example to readme --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 3d8a796..5f45d7a 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,22 @@ or via reference to [a later defined url][massivedynamic], i we so desire. A simple paragraph can contain **bold text**, `inline codeblocks` and *italic text*. We can also link [with a direct url](https://google.com) *(i.e. to google)* or via reference to [a later defined url][massivedynamic], i we so desire. +Paragraphs can be annotated with `id` and `class` attributes: + +```markdown +Paragraphs can be annotated with ids and classes {.thisIsAClass, .anotherClass, #thisIsAnID} +``` + +results in + +Paragraphs can be annotated with ids and classes {.thisIsAClass, .anotherClass, #thisIsAnID} + +```html +

+ Paragraphs can be annotated with ids and classes +

+``` + ### Images ```markdown ![this is an alt text](https://images.unsplash.com/photo-1571171637578-41bc2dd41cd2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&h=300&w=1740&q=80\) -- 2.20.1 From 4e1e44a41bcd16270bb4e75236a4224b5d1f5f4b Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Sun, 21 Aug 2022 12:04:48 +0200 Subject: [PATCH 6/8] added braces to escapable characters --- src/Parser.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index f6d2baf..9855602 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -170,7 +170,8 @@ class Parser { TokenType::BACKTICK, TokenType::ASTERISK, TokenType::LBRACKET, - TokenType::BANG + TokenType::BANG, + TokenType::LBRACE ])) { $this->consume()->data; // backslash $buffer .= $this->consume()->data; @@ -344,7 +345,6 @@ class Parser { private function buildParagraph(array $elms) : void { if (count($elms) < 1) return; - $elm = $this->document->createElement("p"); $i = 0; foreach ($elms as $node) { @@ -375,7 +375,8 @@ class Parser { } $elm = $this->document->createElement("h".$level); foreach ($this->parseText() as $node) - $elm->appendChild($node); + if ($node instanceof DOMNode) + $elm->appendChild($node); $this->document->appendChild($elm); } -- 2.20.1 From 496034258a1731ec906f449da871b25b96eb0aca Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Sun, 21 Aug 2022 12:18:18 +0200 Subject: [PATCH 7/8] fixed annoations breaking headings --- src/Parser.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Parser.php b/src/Parser.php index 9855602..11ab17e 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -310,6 +310,7 @@ class Parser { // then we parse the node content $elm = $this->document->createElement("li"); foreach ($this->parseText() as $node) + if ($node instanceof DOMNode) $elm->appendChild($node); // now we check, if the level of the next line is higher than the current level. -- 2.20.1 From e37050c3f400568c9a00bf2e84fc56ee93c93344 Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Sun, 21 Aug 2022 12:18:38 +0200 Subject: [PATCH 8/8] added tests to check for annotations breaking things --- tests/AnnotationsTest.php | 70 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tests/AnnotationsTest.php diff --git a/tests/AnnotationsTest.php b/tests/AnnotationsTest.php new file mode 100644 index 0000000..953b15b --- /dev/null +++ b/tests/AnnotationsTest.php @@ -0,0 +1,70 @@ +This is an H1 +

This is an H2

+

This is an H3

+

This is an H4

+
This is an H5
+ "; + + [$source, $result] = createTest($source, $target); + $this->assertEquals($source, $result); + } + + public function testAnnotationsDoNotBreakLists() : void { + $source = " + +* this is a list +* with annotations {#someID} + +1. this is an ordered list + 1. with an annotation {.someClass} + +"; + $target = " +
    +
  • this is a list
  • +
  • with annotations
  • +
+
    +
  1. + this is an ordered list +
      +
    1. with an annotation
    2. +
    +
  2. +
+ "; + + [$source, $result] = createTest($source, $target); + $this->assertEquals($source, $result); + } + + public function testAnnotationsDoNotBreakCodeblocks() : void { + $source = " +``` + this is a code block +``` {.someClass} +"; + $target = " +
+			this is a code block
+		
+ "; + + [$source, $result] = createTest($source, $target); + $this->assertEquals($source, $result); + } +} \ No newline at end of file -- 2.20.1