diff --git a/UPGRADE.md b/UPGRADE.md
new file mode 100644
index 00000000..e30fa088
--- /dev/null
+++ b/UPGRADE.md
@@ -0,0 +1,19 @@
+# Upgrade to 0.3
+
+## `DefinitionListTerm::$definitions` is a list of `Node`'s instead of `SpanNode`'s
+
+If you define a custom `definition-list.html.twig`, no longer wrap the value in
+a `
` element (the `.first` and `.last` classes are automatically added):
+
+```diff
+
+ {% for definitionListTerm in definitionList.terms %}
+ - {{ definitionListTerm.term.render()|raw }}
+ -
+ {% for definition in definitionListTerm.definitions %}
+-
{{ definition.render()|raw }}
++ {{ definition.render()|raw }}
+ {% endfor %}
+
+
+```
diff --git a/lib/Parser.php b/lib/Parser.php
index 99df39bd..34044443 100644
--- a/lib/Parser.php
+++ b/lib/Parser.php
@@ -152,6 +152,9 @@ public function createSpanNode($span): SpanNode
return $this->getNodeFactory()->createSpanNode($this, $span);
}
+ /**
+ * Parses the given contents as a new file.
+ */
public function parse(string $contents): DocumentNode
{
$this->getEnvironment()->reset();
@@ -159,6 +162,15 @@ public function parse(string $contents): DocumentNode
return $this->parseLocal($contents);
}
+ /**
+ * Parses the given contents in a new document node.
+ *
+ * CAUTION: This modifies the state of the Parser, do not use this method
+ * on the main parser (use `Parser::getSubParser()->parseLocal(...)` instead).
+ *
+ * Use this method to parse contents of an other node. Nodes created by
+ * this new parser are not added to the main DocumentNode.
+ */
public function parseLocal(string $contents): DocumentNode
{
$this->documentParser = $this->createDocumentParser();
diff --git a/lib/Parser/DefinitionListTerm.php b/lib/Parser/DefinitionListTerm.php
index e8b821d1..3b11b63a 100644
--- a/lib/Parser/DefinitionListTerm.php
+++ b/lib/Parser/DefinitionListTerm.php
@@ -4,6 +4,7 @@
namespace Doctrine\RST\Parser;
+use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\SpanNode;
use RuntimeException;
@@ -15,12 +16,12 @@ class DefinitionListTerm
/** @var SpanNode[] */
private $classifiers = [];
- /** @var SpanNode[] */
+ /** @var Node[] */
private $definitions = [];
/**
* @param SpanNode[] $classifiers
- * @param SpanNode[] $definitions
+ * @param Node[] $definitions
*/
public function __construct(SpanNode $term, array $classifiers, array $definitions)
{
@@ -43,14 +44,14 @@ public function getClassifiers(): array
}
/**
- * @return SpanNode[]
+ * @return Node[]
*/
public function getDefinitions(): array
{
return $this->definitions;
}
- public function getFirstDefinition(): SpanNode
+ public function getFirstDefinition(): Node
{
if (! isset($this->definitions[0])) {
throw new RuntimeException('No definitions found.');
diff --git a/lib/Parser/LineDataParser.php b/lib/Parser/LineDataParser.php
index 624d41ba..81df4964 100644
--- a/lib/Parser/LineDataParser.php
+++ b/lib/Parser/LineDataParser.php
@@ -6,6 +6,7 @@
use Doctrine\Common\EventManager;
use Doctrine\RST\Event\OnLinkParsedEvent;
+use Doctrine\RST\Nodes\ParagraphNode;
use Doctrine\RST\Nodes\SpanNode;
use Doctrine\RST\Parser;
@@ -147,27 +148,42 @@ public function parseListLine(string $line): ?ListLine
*/
public function parseDefinitionList(array $lines): DefinitionList
{
- $definitionList = [];
+ /** @var array{term: SpanNode, classifiers: list, definition: string}|null $definitionListTerm */
$definitionListTerm = null;
- $currentDefinition = null;
+ $definitionList = [];
+
+ $createDefinitionTerm = function (array $definitionListTerm): DefinitionListTerm {
+ // parse any markup in the definition (e.g. lists, directives)
+ $definitionNodes = $this->parser->getSubParser()->parseLocal($definitionListTerm['definition'])->getNodes();
+ if (count($definitionNodes) === 1 && $definitionNodes[0] instanceof ParagraphNode) {
+ // if there is only one paragraph node, the value is put directly in the element
+ $definitionNodes = [$definitionNodes[0]->getValue()];
+ } else {
+ // otherwise, .first and .last are added to the first and last nodes of the definition
+ $definitionNodes[0]->setClasses($definitionNodes[0]->getClasses() + ['first']);
+ $definitionNodes[count($definitionNodes) - 1]->setClasses($definitionNodes[count($definitionNodes) - 1]->getClasses() + ['last']);
+ }
+
+ return new DefinitionListTerm(
+ $definitionListTerm['term'],
+ $definitionListTerm['classifiers'],
+ $definitionNodes
+ );
+ };
foreach ($lines as $key => $line) {
- // term definition line
- if ($definitionListTerm !== null && substr($line, 0, 4) === ' ') {
- $definition = trim($line);
+ // indent or empty line = term definition line
+ if ($definitionListTerm !== null && (substr($line, 0, 4) === ' ' || trim($line) === '')) {
+ $definition = substr($line, 4);
- $currentDefinition .= $definition . ' ';
+ $definitionListTerm['definition'] .= $definition . "\n";
- // non empty string
+ // non empty string at the start of the line = definition term
} elseif (trim($line) !== '') {
// we are starting a new term so if we have an existing
// term with definitions, add it to the definition list
if ($definitionListTerm !== null) {
- $definitionList[] = new DefinitionListTerm(
- $definitionListTerm['term'],
- $definitionListTerm['classifiers'],
- $definitionListTerm['definitions']
- );
+ $definitionList[] = $createDefinitionTerm($definitionListTerm);
}
$parts = explode(':', trim($line));
@@ -182,31 +198,16 @@ public function parseDefinitionList(array $lines): DefinitionList
$definitionListTerm = [
'term' => $this->parser->createSpanNode($term),
'classifiers' => $classifiers,
- 'definitions' => [],
+ 'definition' => '',
];
-
- // last line
- } elseif ($definitionListTerm !== null && count($lines) - 1 === $key) {
- if ($currentDefinition !== null) {
- $definitionListTerm['definitions'][] = $this->parser->createSpanNode($currentDefinition);
-
- $currentDefinition = null;
- }
-
- $definitionList[] = new DefinitionListTerm(
- $definitionListTerm['term'],
- $definitionListTerm['classifiers'],
- $definitionListTerm['definitions']
- );
-
- // empty line, start of a new definition for the current term
- } elseif ($currentDefinition !== null && $definitionListTerm !== null) {
- $definitionListTerm['definitions'][] = $this->parser->createSpanNode($currentDefinition);
-
- $currentDefinition = null;
}
}
+ // append the last definition of the list
+ if ($definitionListTerm !== null) {
+ $definitionList[] = $createDefinitionTerm($definitionListTerm);
+ }
+
return new DefinitionList($definitionList);
}
}
diff --git a/lib/Templates/default/html/definition-list.html.twig b/lib/Templates/default/html/definition-list.html.twig
index bea3bcb7..668f799a 100644
--- a/lib/Templates/default/html/definition-list.html.twig
+++ b/lib/Templates/default/html/definition-list.html.twig
@@ -14,21 +14,11 @@
{% endif %}
- {% if definitionListTerm.definitions|length > 1 %}
-
- {% for definition in definitionListTerm.definitions %}
- {% if loop.first %}
- {{ definition.render()|raw }}
- {% elseif loop.last %}
- {{ definition.render()|raw }}
- {% else %}
- {{ definition.render()|raw }}
- {% endif %}
- {% endfor %}
-
- {% elseif definitionListTerm.definitions|length == 1 %}
- {{ definitionListTerm.firstDefinition.render()|raw }}
- {% endif %}
+
+ {% for definition in definitionListTerm.definitions %}
+ {{ definition.render()|raw }}
+ {% endfor %}
+
{% endfor %}
{% endapply %}
diff --git a/tests/Functional/tests/class-directive/class-directive.html b/tests/Functional/tests/class-directive/class-directive.html
index 37ec2b10..f324a102 100644
--- a/tests/Functional/tests/class-directive/class-directive.html
+++ b/tests/Functional/tests/class-directive/class-directive.html
@@ -17,7 +17,7 @@
- term 1
- - Definition 1
+ - Definition 1
diff --git a/tests/Functional/tests/definition-list/definition-list.html b/tests/Functional/tests/definition-list/definition-list.html
index 4e5606d2..b0338b41 100644
--- a/tests/Functional/tests/definition-list/definition-list.html
+++ b/tests/Functional/tests/definition-list/definition-list.html
@@ -8,33 +8,35 @@
Text around the definition list.
- term 1
- - Definition 1
+ - Definition 1
- term 2
-
-
Definition 1
- Definition 2
- Definition 3
+ Definition 1
+ Definition 2
+ Definition 3
- term 3 :classifier
- - Definition 1
+ - Definition 1
- term 4 :classifier one:classifier two
- - Definition 1
+ - Definition 1
- term with & :classifier with &
- - Definition 1 with &
+ - Definition 1 with &
- term with & :classifier with &:classifier with &
-
-
Definition 1 with &
- Definition 2 with &
+ Definition 1 with &
+ Definition 2 with &
-
term 5
:
classifier
- - Definition 1
+ - Definition 1
- multi-line definition term
-
-
Definition 1 line 1 Definition 1 line 2
- Definition 2 line 1 Definition 2 line 2
+ Definition 1 line 1
+Definition 1 line 2
+ Definition 2 line 1
+Definition 2 line 2
@@ -47,13 +49,15 @@
- term 1
-
-
Definition 1 line 1 Definition 1 line 2
- Definition 2
+ Definition 1 line 1
+Definition 1 line 2
+ Definition 2
- term 2
-
-
Definition 1 line 1 Definition 1 line 2
- Definition 2
+ Definition 1 line 1
+Definition 1 line 2
+ Definition 2
@@ -65,11 +69,26 @@
Paragraph 1
- term 1
- - definition 1 definition 2
+ - definition 1
+definition 2
Paragraph 2
- term 2
- - definition 1 definition 2
+ - definition 1
+definition 2
+
+
+
+
+ Directive in definition list
+
+
+ - term 1
+ -
+
+
directive in definition list
+
+
diff --git a/tests/Functional/tests/definition-list/definition-list.rst b/tests/Functional/tests/definition-list/definition-list.rst
index 37b243dd..c270e426 100644
--- a/tests/Functional/tests/definition-list/definition-list.rst
+++ b/tests/Functional/tests/definition-list/definition-list.rst
@@ -73,3 +73,11 @@ Paragraph 2
term 2
definition 1
definition 2
+
+Directive in definition list
+============================
+
+term 1
+ .. note::
+
+ directive in definition list
diff --git a/tests/Functional/tests/standalone-hyperlinks/standalone-hyperlinks.html b/tests/Functional/tests/standalone-hyperlinks/standalone-hyperlinks.html
index 71652f8a..c867ff85 100644
--- a/tests/Functional/tests/standalone-hyperlinks/standalone-hyperlinks.html
+++ b/tests/Functional/tests/standalone-hyperlinks/standalone-hyperlinks.html
@@ -20,10 +20,31 @@
mailto:name@example.comhttp://www.asianewsphoto.com/(S(neugxif4twuizg551ywh3f55))/Web_ENG/View_DetailPhoto.aspx?PicId=752http://www.asianewsphoto.com/(S(neugxif4twuizg551ywh3f55))http://lcweb2.loc.gov/cgi-bin/query/h?pp/horyd:@field(NUMBER+@band(thc+5a46634))http://www.example.com/wpstyle/?p=364https://www.example.com/foo/?bar=baz&inga=42&quuxhttp://userid:password@example.com:8080http://userid:password@example.com:8080/http://userid@example.comhttp://userid@example.com/http://userid@example.com:8080http://userid@example.com:8080/http://userid:password@example.comhttp://userid:password@example.com/http://142.42.1.1/http://142.42.1.1:8080/http://⌘.wshttp://⌘.ws/http://☺.damowmow.com/http://code.google.com/events/#&product=browserhttp://j.mpftp://foo.bar/bazhttp://foo.bar/?q=Test%20URL-encoded%20stuffhttp://例子.测试http://उदाहरण.परीक्षाhttp://-._!$&'()*+,;=:%40:80%2f::::::@example.comhttp://1337.nethttp://a.b-c.dehttp://223.255.255.254mailto:jane.doe@example.comchrome://chromeirc://irc.freenode.net:6667/freenodemicrosoft.windows.camera:foobarcoaps+ws://foobar
How about multiple http://example.com/uris on the mailto:same-line@example.com
-
- - Should fail against :
- - 6:00p filename.txt www.c.ws/䨹 Just a www.example.com link. bit.ly/foo “is.gd/foo/” WWW.EXAMPLE.COM http:// http://. http://.. http://? http://?? // //a /// foo.com h://test http:// shouldfail.com :// should fail ✪df.ws/1234 example.com example.com/
-
+Should fail against:
+
+ 6:00p
+filename.txt
+www.c.ws/䨹
+Just a www.example.com link.
+bit.ly/foo
+“is.gd/foo/”
+WWW.EXAMPLE.COM
+http://
+http://.
+http://..
+http://?
+http://??
+//
+//a
+///
+foo.com
+h://test
+http:// shouldfail.com
+:// should fail
+✪df.ws/1234
+example.com
+example.com/
+
These are currently problematic and fail, since the parser appears to see named
links appearing within these URLs (i.e. "blah_") and attempts to replace these
with tokens. These should match the standalone hyperlink pattern, but they do
diff --git a/tests/Functional/tests/standalone-hyperlinks/standalone-hyperlinks.rst b/tests/Functional/tests/standalone-hyperlinks/standalone-hyperlinks.rst
index d55aa397..406e9b96 100644
--- a/tests/Functional/tests/standalone-hyperlinks/standalone-hyperlinks.rst
+++ b/tests/Functional/tests/standalone-hyperlinks/standalone-hyperlinks.rst
@@ -64,6 +64,7 @@ Matches the right thing in the following lines:
How about multiple http://example.com/uris on the mailto:same-line@example.com
Should fail against:
+
6:00p
filename.txt
www.c.ws/䨹