Browse Source

Making more progress

pretty-print
Dustin Wilson 3 years ago
parent
commit
12b90b92d0
  1. 191
      lib/Parser/Serializer.php
  2. 1043
      old/Document.php

191
lib/Parser/Serializer.php

@ -97,18 +97,11 @@ abstract class Serializer {
if ($reformatWhitespace) {
$hasChildNodes = $n->hasChildNodes();
$modify = false;
$isPreformattedContent = self::isPreformattedContent($n);
// If the node is an HTML element and its tag name is in the list of
// preformatted elements or if the node is not an html element and if the
// element is preformatted content then there's no need to modify.
if ((($htmlElement && in_array($tagName, self::PREFORMATTED_ELEMENTS)) || !$htmlElement) && $isPreformattedContent) {
$modify = false;
}
// If the node is an HTML element, and either its tag name is in the list of
// elements to be treated as block for the purposes of serialization or the
// element itself is to be treated as block then we need to modify whitespace.
elseif ($htmlElement) {
if ($htmlElement) {
if (in_array($tagName, self::BLOCK_ELEMENTS) || self::treatAsBlock($n)) {
$modify = true;
}
@ -122,7 +115,7 @@ abstract class Serializer {
// Otherwise, walk up the DOM and find the root foreign ancestor. If that
// ancestor is to be treated as block then we need to modify whitespace.
else {
$modify = self::treatForeignContentAsBlock($n);
$modify = self::treatForeignRootAsBlock($n);
}
}
@ -143,9 +136,8 @@ abstract class Serializer {
$s .= "\n";
}
//if (!$first) {
$s .= "\n" . str_repeat($indentChar, $indentionLevel * $indentStep);
//}
$s .= "\n" . str_repeat($indentChar, $indentionLevel * $indentStep);
}
}
@ -235,19 +227,21 @@ abstract class Serializer {
if (($n->namespaceURI ?? Parser::HTML_NAMESPACE) !== Parser::HTML_NAMESPACE || !in_array($tagName, self::VOID_ELEMENTS)) {
# If the node is a template element, then let the node instead be the template
# element's template contents (a DocumentFragment node).
if ($htmlElement && $n->tagName === "template") {
if ($htmlElement && $tagName === "template") {
// NOTE: Templates are handled by their own serializer
// Disable pretty printing when serializing templates in preformatted content
$templateConfig = $config;
$isPreformattedContent = self::isPreformattedContent($n);
if ($reformatWhitespace && $isPreformattedContent) {
$config->reformatWhitespace = false;
$templateConfig->reformatWhitespace = false;
}
$ss = self::serializeTemplate($n, $config);
$ss = self::serializeTemplate($n, $templateConfig);
// If reformatting whitespace indention needs to be applied to the template's
// serialized contents if not preformatted content.
if ($reformatWhitespace && !$isPreformattedContent && $indentionLevel > 0) {
$ss = explode("\n", $ss);
$ss = explode("\n", $ss);
foreach ($ss as $key => $value) {
$ss[$key] = str_repeat($indentChar, $indentionLevel * $indentStep) . $ss[$key];
}
@ -258,11 +252,8 @@ abstract class Serializer {
if ($reformatWhitespace) {
// If formatting output and the element's whitespace has already been modified
// increment the indention level
if ($modify) {
$indentionLevel++;
}
$modifyStack[] = $modify;
$indentionLevel++;
$prettyPrintStack[] = $n;
}
// If the element has children, store its tag name and continue the loop with
@ -272,19 +263,6 @@ abstract class Serializer {
continue;
}
if ($reformatWhitespace) {
if (end($modifyStack)) {
// Decrement the indention level.
$indentionLevel--;
// If a foreign element that isn't preformatted content and its root foreign
// element is to be treated as block then add whitespace.
if (!$htmlElement && self::treatForeignContentAsBlock($n)) {
$s .= "\n" . str_repeat($indentChar, $indentionLevel * $indentStep);
}
}
}
// Otherwise just append the end tag now
$s .= "</$tagName>";
}
@ -306,11 +284,12 @@ abstract class Serializer {
else {
$t = $n->data;
if ($reformatWhitespace && !self::isPreformattedContent($n)) {
if (self::treatAsBlock($n) || self::treatForeignContentAsBlock($n)) {
if (self::treatAsBlock($n) || self::treatForeignRootAsBlock($n)) {
// If the text node's data is made up of only whitespace characters continue
// onto the next node
if (strspn($t, Data::WHITESPACE) === strlen($t)) {
continue;
// FIXME: this is temporary
goto next;
}
}
@ -323,22 +302,40 @@ abstract class Serializer {
}
# If current node is a Comment
elseif ($n instanceof \DOMComment) {
if ($reformatWhitespace /*&& !$first*/ && !self::isPreformattedContent($n) && (self::treatAsBlock($n) || self::treatForeignContentAsBlock($n))) {
$previousNonTextNodeSiblingName = null;
$nn = $n;
while ($nn = $nn->previousSibling) {
if (!$nn instanceof \DOMText) {
$previousNonTextNodeSiblingName = $nn->nodeName;
break;
if ($reformatWhitespace && !self::isPreformattedContent($n)) {
$modify = false;
$parentIsHTMLElement = (($n->parentNode->namespaceURI ?? Parser::HTML_NAMESPACE) !== Parser::HTML_NAMESPACE);
if ($parentIsHTMLElement) {
if (self::treatAsBlock($n)) {
$modify = true;
}
} else {
if ($n->parentNode->parentNode !== null && ($n->parentNode->parentNode->namespaceURI ?? Parser::HTML_NAMESPACE) === Parser::HTML_NAMESPACE) {
if (self::treatAsBlock($n)) {
$modify = true;
}
} elseif (self::treatForeignRootAsBlock($n)) {
$modify = true;
}
}
// Add an additional newline if the previous sibling wasn't a comment.
if ($previousNonTextNodeSiblingName !== null && $previousNonTextNodeSiblingName !== $this->nodeName) {
$s .= "\n";
}
if ($modify) {
$previousNonTextNodeSiblingName = null;
$nn = $n;
while ($nn = $nn->previousSibling) {
if (!$nn instanceof \DOMText) {
$previousNonTextNodeSiblingName = $nn->nodeName;
break;
}
}
// Add an additional newline if the previous sibling wasn't a comment.
if ($previousNonTextNodeSiblingName !== null && $previousNonTextNodeSiblingName !== $n->nodeName) {
$s .= "\n";
}
$s .= "\n" . str_repeat($indentChar, $indentionLevel * $indentStep);
$s .= "\n" . str_repeat($indentChar, $indentionLevel * $indentStep);
}
}
# Append the literal string "<!--" (U+003C LESS-THAN SIGN,
@ -351,22 +348,40 @@ abstract class Serializer {
}
# If current node is a ProcessingInstruction
elseif ($n instanceof \DOMProcessingInstruction) {
if ($reformatWhitespace /* && !$first */ && !self::isPreformattedContent($n) && (self::treatAsBlock($n) || self::treatForeignContentAsBlock($n))) {
$previousNonTextNodeSiblingName = null;
$nn = $n;
while ($nn = $n->previousSibling) {
if (!$nn instanceof \DOMText) {
$previousNonTextNodeSiblingName = $nn->nodeName;
break;
if ($reformatWhitespace && !self::isPreformattedContent($n)) {
$modify = false;
$parentIsHTMLElement = (($n->parentNode->namespaceURI ?? Parser::HTML_NAMESPACE) !== Parser::HTML_NAMESPACE);
if ($parentIsHTMLElement) {
if (self::treatAsBlock($n)) {
$modify = true;
}
} else {
if ($n->parentNode->parentNode !== null && ($n->parentNode->parentNode->namespaceURI ?? Parser::HTML_NAMESPACE) === Parser::HTML_NAMESPACE) {
if (self::treatAsBlock($n)) {
$modify = true;
}
} elseif (self::treatForeignRootAsBlock($n)) {
$modify = true;
}
}
// Add an additional newline if the previous sibling wasn't a comment.
if ($previousNonTextNodeSiblingName !== null && $previousNonTextNodeSiblingName !== $this->nodeName) {
$s .= "\n";
}
if ($modify) {
$previousNonTextNodeSiblingName = null;
$nn = $n;
while ($nn = $nn->previousSibling) {
if (!$nn instanceof \DOMText) {
$previousNonTextNodeSiblingName = $nn->nodeName;
break;
}
}
$s .= "\n" . str_repeat($indentChar, $indentionLevel * $indentStep);
// Add an additional newline if the previous sibling wasn't a comment.
if ($previousNonTextNodeSiblingName !== null && $previousNonTextNodeSiblingName !== $n->nodeName) {
$s .= "\n";
}
$s .= "\n" . str_repeat($indentChar, $indentionLevel * $indentStep);
}
}
# Append the literal string "<?" (U+003C LESS-THAN SIGN,
@ -396,15 +411,55 @@ abstract class Serializer {
} else {
throw new Exception(Exception::UNSUPPORTED_NODE_TYPE, [get_class($n)]);
}
next:
// If the current node has no more siblings, go up the tree till a
// sibling is found or we've reached the original node
while (!$n->nextSibling && $stack) {
// Write out the stored end tag each time we go up the tree
$tagName = array_pop($stack);
if ($reformatWhitespace) {
array_pop($modifyStack);
$indentionLevel--;
$tag = array_pop($prettyPrintStack);
$modify = false;
if (!self::isPreformattedContent($n)) {
if (($tag->namespaceURI ?? Parser::HTML_NAMESPACE) === Parser::HTML_NAMESPACE) {
if (self::treatAsBlock($tag->firstChild)) {
$modify = true;
}
} else {
$firstElementChild = null;
if (property_exists($tag, 'firstElementChild')) {
$firstElementChild = $tag->firstElementChild;
} else {
$t = $tag->firstChild;
do {
if ($t instanceof \DOMElement) {
$firstElementChild = $t;
break;
}
} while ($t = $t->nextSibling);
}
if ($firstElementChild !== null) {
if (($tag->parentNode->namespaceURI ?? Parser::HTML_NAMESPACE) === Parser::HTML_NAMESPACE) {
if (self::treatAsBlock($tag)) {
$modify = true;
}
} elseif (self::treatForeignRootAsBlock($tag)) {
$modify = true;
}
}
}
}
if ($modify) {
$s .= "\n" . str_repeat($indentChar, $indentionLevel * $indentStep);
}
}
// Write out the stored end tag each time we go up the tree
$tagName = array_pop($stack);
$s .= "</$tagName>";
$n = $n->parentNode;
}
@ -472,11 +527,11 @@ abstract class Serializer {
// be able to moonwalk through document fragment hosts.
$n = $node;
while ($n = $n->parentNode) {
do {
if ($n instanceof \DOMElement && ($n->namespaceURI ?? Parser::HTML_NAMESPACE) === Parser::HTML_NAMESPACE && in_array($n->tagName, self::PREFORMATTED_ELEMENTS)) {
return true;
}
}
} while ($n = $n->parentNode);
return false;
}
@ -491,11 +546,15 @@ abstract class Serializer {
return false;
}
if ($node->parentNode instanceof \DOMDocument) {
return true;
}
$xpath = new \DOMXPath($node->ownerDocument);
return ($xpath->evaluate(self::BLOCK_QUERY, $node->parentNode) > 0);
}
protected static function treatForeignContentAsBlock(\DOMNode $node): bool {
protected static function treatForeignRootAsBlock(\DOMNode $node): bool {
// NOTE: This method is used only when pretty printing. Implementors of userland
// PHP DOM solutions with template contents will need to extend this method to
// be able to moonwalk through document fragment hosts.

1043
old/Document.php

File diff suppressed because it is too large
Loading…
Cancel
Save