Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. Renderer.php

class Renderer

Same name in this branch
  1. 11.1.x vendor/phpunit/php-code-coverage/src/Report/Html/Renderer.php \SebastianBergmann\CodeCoverage\Report\Html\Renderer
  2. 11.1.x core/lib/Drupal/Core/Render/Renderer.php \Drupal\Core\Render\Renderer

Nodes renderer class

@author Marco Marchiò <marco.mm89@gmail.com>

Hierarchy

  • class \Peast\Renderer

Expanded class hierarchy of Renderer

1 file declares its use of Renderer
JsOptimizer.php in core/lib/Drupal/Core/Asset/JsOptimizer.php
46 string references to 'Renderer'
BreakLockLink::create in core/lib/Drupal/Core/TempStore/Element/BreakLockLink.php
Creates an instance of the plugin.
CommentForm::create in core/modules/comment/src/CommentForm.php
Instantiates a new instance of this class.
ConfigSingleImportForm::create in core/modules/config/src/Form/ConfigSingleImportForm.php
Instantiates a new instance of this class.
ConfigSync::create in core/modules/config/src/Form/ConfigSync.php
Instantiates a new instance of this class.
ConfigTranslationController::create in core/modules/config_translation/src/Controller/ConfigTranslationController.php
Instantiates a new instance of the implementing class using autowiring.

... See full list

File

vendor/mck89/peast/lib/Peast/Renderer.php, line 19

Namespace

Peast
View source
class Renderer {
    
    /**
     * Formatter to use for the rendering
     * 
     * @var Formatter\Base
     */
    protected $formatter;
    
    /**
     * Rendering options taken from the formatter
     * 
     * @var object
     */
    protected $renderOpts;
    
    /**
     * Node types that does not require semicolon insertion
     * 
     * @var array
     */
    protected $noSemicolon = array(
        "ClassDeclaration",
        "ExportDefaultDeclaration",
        "ForInStatement",
        "ForOfStatement",
        "ForStatement",
        "FunctionDeclaration",
        "IfStatement",
        "LabeledStatement",
        "StaticBlock",
        "SwitchStatement",
        "TryStatement",
        "WhileStatement",
        "WithStatement",
        "MethodDefinition",
    );
    
    /**
     * Sets the formatter to use for the rendering
     * 
     * @param Formatter\Base    $formatter  Formatter
     * 
     * @return $this
     */
    public function setFormatter(Formatter\Base $formatter) {
        $this->formatter = $formatter;
        $this->renderOpts = (object) array(
            "nl" => $this->formatter
                ->getNewLine(),
            "ind" => $this->formatter
                ->getIndentation(),
            "nlbc" => $this->formatter
                ->getNewLineBeforeCurlyBracket(),
            "sao" => $this->formatter
                ->getSpacesAroundOperator() ? " " : "",
            "sirb" => $this->formatter
                ->getSpacesInsideRoundBrackets() ? " " : "",
            "awb" => $this->formatter
                ->getAlwaysWrapBlocks(),
            "com" => $this->formatter
                ->getRenderComments(),
            "rci" => $this->formatter
                ->getRecalcCommentsIndent(),
        );
        return $this;
    }
    
    /**
     * Returns the formatter to use for the rendering
     * 
     * @return Formatter\Base
     */
    public function getFormatter() {
        return $this->formatter;
    }
    
    /**
     * Renders the given node
     * 
     * @param Syntax\Node\Node  $node   Node to render
     * 
     * @return string
     * 
     * @throws \Exception
     */
    public function render(Syntax\Node\Node $node) {
        
        //Throw exception if no formatter has been specified
        if (!$this->formatter) {
            throw new \Exception("Formatter not set");
        }
        
        //Reset indentation level
        $this->renderOpts->indLevel = 0;
        
        //Start rendering
        return $this->renderNode($node);
    }
    
    /**
     * Renders a node
     * 
     * @param Syntax\Node\Node  $node           Node to render
     * @param bool              $addSemicolon   True to add semicolon after node
     *                                          rendered code
     * 
     * @return string
     */
    protected function renderNode(Syntax\Node\Node $node, $addSemicolon = false) {
        $code = "";
        if ($this->renderOpts->com) {
            $code .= $this->renderComments($node);
        }
        $type = $node->getType();
        switch ($type) {
            case "ArrayExpression":
            case "ArrayPattern":
                $code .= "[" . $this->joinNodes($node->getElements(), "," . $this->renderOpts->sao) . "]";
                break;
            case "ArrowFunctionExpression":
                if ($node->getAsync()) {
                    $code .= "async" . $this->renderOpts->sao;
                }
                $code .= "(" . $this->renderOpts->sirb . $this->joinNodes($node->getParams(), "," . $this->renderOpts->sao) . $this->renderOpts->sirb . ")" . $this->renderOpts->sao . "=>";
                $body = $node->getBody();
                if ($body->getType() !== "BlockStatement") {
                    $code .= $this->renderOpts->sao . $this->renderNode($body);
                }
                else {
                    $code .= $this->renderStatementBlock($node, $body, true);
                }
                break;
            case "AwaitExpression":
                $code .= "await " . $this->renderNode($node->getArgument());
                break;
            case "AssignmentExpression":
            case "AssignmentPattern":
            case "BinaryExpression":
            case "LogicalExpression":
                $operator = $type === "AssignmentPattern" ? "=" : $node->getOperator();
                $code .= $this->renderNode($node->getLeft());
                $codeRight = $this->renderNode($node->getRight());
                if (preg_match("#^[a-z]+\$#i", $operator)) {
                    $code .= " " . $operator . " ";
                }
                else {
                    
                    //If there's no space around the operator, additional checks must
                    
                    //be performed to prevent errors when rendering unary and update
                    
                    //expressions inside binary expressions
                    $checkSpace = !$this->renderOpts->sao && $type === "BinaryExpression";
                    
                    //The space is mandatory if the left part ends with the same
                    
                    //character used as operator
                    if ($checkSpace && $code && substr($code, -1) === $operator) {
                        $code .= " ";
                    }
                    $code .= $this->renderOpts->sao . $operator . $this->renderOpts->sao;
                    
                    //The space is mandatory if the right part begins with the same
                    
                    //character used as operator
                    if ($checkSpace && $codeRight && $codeRight[0] === $operator) {
                        $code .= " ";
                    }
                }
                $code .= $codeRight;
                break;
            case "BlockStatement":
            case "ClassBody":
            case "Program":
                $code .= $this->renderStatementBlock($node, $node->getBody(), false, false, true, false);
                break;
            case "BreakStatement":
            case "ContinueStatement":
                $code .= $type === "BreakStatement" ? "break" : "continue";
                if ($label = $node->getLabel()) {
                    $code .= " " . $this->renderNode($label);
                }
                break;
            case "CallExpression":
            case "NewExpression":
                if ($type === "NewExpression") {
                    $code .= "new ";
                    $optional = false;
                }
                else {
                    $optional = $node->getOptional();
                }
                $code .= $this->renderNode($node->getCallee()) . ($optional ? "?." : "") . "(" . $this->renderOpts->sirb . $this->joinNodes($node->getArguments(), "," . $this->renderOpts->sao) . $this->renderOpts->sirb . ")";
                break;
            case "CatchClause":
                $code .= "catch";
                if ($params = $node->getParam()) {
                    $code .= $this->renderOpts->sao . "(" . $this->renderOpts->sirb . $this->renderNode($params) . $this->renderOpts->sirb . ")";
                }
                $code .= $this->renderStatementBlock($node, $node->getBody(), true);
                break;
            case "ChainExpression":
            case "ExpressionStatement":
                $code .= $this->renderNode($node->getExpression());
                break;
            case "ClassExpression":
            case "ClassDeclaration":
                $code .= "class";
                if ($id = $node->getId()) {
                    $code .= " " . $this->renderNode($id);
                }
                if ($superClass = $node->getSuperClass()) {
                    $code .= " extends " . $this->renderNode($superClass);
                }
                $code .= $this->renderStatementBlock($node, $node->getBody(), true);
                break;
            case "ConditionalExpression":
                $code .= $this->renderNode($node->getTest()) . $this->renderOpts->sao . "?" . $this->renderOpts->sao . $this->renderNode($node->getConsequent()) . $this->renderOpts->sao . ":" . $this->renderOpts->sao . $this->renderNode($node->getAlternate());
                break;
            case "DebuggerStatement":
                $code .= "debugger";
                break;
            case "DoWhileStatement":
                $code .= "do" . $this->renderStatementBlock($node, $node->getBody(), null, true) . $this->renderOpts->sao . "while" . $this->renderOpts->sao . "(" . $this->renderOpts->sirb . $this->renderNode($node->getTest()) . $this->renderOpts->sirb . ")";
                break;
            case "JSXEmptyExpression":
            case "EmptyStatement":
                break;
            case "ExportAllDeclaration":
                $code .= "export *";
                $exported = $node->getExported();
                if ($exported) {
                    $code .= " as " . $this->renderNode($exported);
                }
                $code .= " from " . $this->renderNode($node->getSource());
                break;
            case "ExportDefaultDeclaration":
                $declaration = $node->getDeclaration();
                $code .= "export default " . $this->renderNode($declaration);
                if ($this->requiresSemicolon($declaration)) {
                    $code .= ";";
                }
                break;
            case "ExportNamedDeclaration":
                $code .= "export";
                if ($dec = $node->getDeclaration()) {
                    $code .= " " . $this->renderNode($dec);
                }
                else {
                    $code .= $this->renderOpts->sao . "{" . $this->joinNodes($node->getSpecifiers(), "," . $this->renderOpts->sao) . "}";
                    if ($source = $node->getSource()) {
                        $code .= $this->renderOpts->sao . "from " . $this->renderNode($source);
                    }
                }
                break;
            case "ExportSpecifier":
                $local = $this->renderNode($node->getLocal());
                $ref = $this->renderNode($node->getExported());
                $code .= $local === $ref ? $local : $local . " as " . $ref;
                break;
            case "ForInStatement":
            case "ForOfStatement":
                
                //Force single line mode for substatements
                $this->renderOpts->forceSingleLine = true;
                $code .= "for" . ($type === "ForOfStatement" && $node->getAwait() ? " await" : "") . $this->renderOpts->sao . "(" . $this->renderOpts->sirb . $this->renderNode($node->getLeft()) . " " . ($type === "ForInStatement" ? "in" : "of") . " " . $this->renderNode($node->getRight()) . $this->renderOpts->sirb . ")" . $this->renderStatementBlock($node, $node->getBody());
                unset($this->renderOpts->forceSingleLine);
                break;
            case "ForStatement":
                
                //Force single line mode for substatements
                $this->renderOpts->forceSingleLine = true;
                $code .= "for" . $this->renderOpts->sao . "(" . $this->renderOpts->sirb;
                if ($init = $node->getInit()) {
                    $code .= $this->renderNode($init);
                }
                $code .= ";" . $this->renderOpts->sao;
                if ($test = $node->getTest()) {
                    $code .= $this->renderNode($test);
                }
                $code .= ";" . $this->renderOpts->sao;
                if ($update = $node->getUpdate()) {
                    $code .= $this->renderNode($update);
                }
                $code .= $this->renderOpts->sirb . ")" . $this->renderStatementBlock($node, $node->getBody());
                unset($this->renderOpts->forceSingleLine);
                break;
            case "FunctionDeclaration":
            case "FunctionExpression":
                $id = $node->getId();
                if ($node->getAsync()) {
                    $code .= "async ";
                }
                $code .= "function";
                if ($node->getGenerator()) {
                    $code .= $this->renderOpts->sao . "*";
                }
                elseif ($id) {
                    $code .= " ";
                }
                if ($id) {
                    if ($node->getGenerator()) {
                        $code .= $this->renderOpts->sao;
                    }
                    $code .= $this->renderNode($id);
                }
                $code .= $this->renderOpts->sao . "(" . $this->renderOpts->sirb . $this->joinNodes($node->getParams(), "," . $this->renderOpts->sao) . $this->renderOpts->sirb . ")" . $this->renderStatementBlock($node, $node->getBody(), true);
                break;
            case "ImportExpression":
                $code .= "import(" . $this->renderOpts->sirb . $this->renderNode($node->getSource()) . $this->renderOpts->sirb . ")";
                break;
            case "JSXIdentifier":
            case "Identifier":
                $code .= $node->getRawName();
                break;
            case "IfStatement":
                $code .= "if" . $this->renderOpts->sao . "(" . $this->renderOpts->sirb . $this->renderNode($node->getTest()) . $this->renderOpts->sirb . ")";
                $code .= $this->renderStatementBlock($node, $node->getConsequent());
                if ($alternate = $node->getAlternate()) {
                    $code .= $this->renderOpts->sao . "else" . $this->renderStatementBlock($node, $alternate, null, true);
                }
                break;
            case "ImportDeclaration":
                $code .= "import ";
                $specifiers = $node->getSpecifiers();
                if (count($specifiers)) {
                    $sep = "," . $this->renderOpts->sao;
                    $groups = $parts = array();
                    foreach ($specifiers as $spec) {
                        $specType = $spec->getType();
                        if (!isset($groups[$specType])) {
                            $groups[$specType] = array();
                        }
                        $groups[$specType][] = $spec;
                    }
                    if (isset($groups["ImportDefaultSpecifier"])) {
                        foreach ($groups["ImportDefaultSpecifier"] as $s) {
                            $parts[] = $this->renderNode($s);
                        }
                    }
                    if (isset($groups["ImportNamespaceSpecifier"])) {
                        foreach ($groups["ImportNamespaceSpecifier"] as $s) {
                            $parts[] = $this->renderNode($s);
                        }
                    }
                    if (isset($groups["ImportSpecifier"])) {
                        $impSpec = array();
                        foreach ($groups["ImportSpecifier"] as $s) {
                            $impSpec[] = $this->renderNode($s);
                        }
                        $parts[] = "{" . implode($sep, $impSpec) . "}";
                    }
                    $code .= implode($sep, $parts) . " from ";
                }
                $code .= $this->renderNode($node->getSource());
                break;
            case "ImportDefaultSpecifier":
                $code .= $this->renderNode($node->getLocal());
                break;
            case "ImportNamespaceSpecifier":
                $code .= "* as " . $this->renderNode($node->getLocal());
                break;
            case "ImportSpecifier":
                $local = $this->renderNode($node->getLocal());
                $ref = $this->renderNode($node->getImported());
                $code .= $local === $ref ? $local : $ref . " as " . $local;
                break;
            case "JSXAttribute":
                $code .= $this->renderNode($node->getName());
                if ($value = $node->getValue()) {
                    $code .= "=" . $this->renderNode($value);
                }
                break;
            case "JSXClosingElement":
                $code .= "</" . $this->renderNode($node->getName()) . ">";
                break;
            case "JSXClosingFragment":
                $code .= "</>";
                break;
            case "JSXElement":
                $code .= $this->renderNode($node->getOpeningElement()) . $this->joinNodes($node->getChildren(), "");
                if ($closing = $node->getClosingElement()) {
                    $code .= $this->renderNode($closing);
                }
                break;
            case "JSXExpressionContainer":
                $code .= "{" . $this->renderNode($node->getExpression()) . "}";
                break;
            case "JSXFragment":
                $code .= $this->renderNode($node->getOpeningFragment()) . $this->joinNodes($node->getChildren(), "") . $this->renderNode($node->getClosingFragment());
                break;
            case "JSXNamespacedName":
                $code .= $this->renderNode($node->getNamespace()) . ":" . $this->renderNode($node->getName());
                break;
            case "JSXOpeningElement":
                $code .= "<" . $this->renderNode($node->getName());
                $attributes = $node->getAttributes();
                if (count($attributes)) {
                    $code .= " " . $this->joinNodes($attributes, " ");
                }
                if ($node->getSelfClosing()) {
                    $code .= "/";
                }
                $code .= ">";
                break;
            case "JSXOpeningFragment":
                $code .= "<>";
                break;
            case "JSXSpreadAttribute":
                $code .= "{..." . $this->renderNode($node->getArgument()) . "}";
                break;
            case "JSXSpreadChild":
                $code .= "{..." . $this->renderNode($node->getExpression()) . "}";
                break;
            case "LabeledStatement":
                $body = $node->getBody();
                $code .= $this->renderNode($node->getLabel()) . ":";
                if ($body->getType() === "BlockStatement") {
                    $code .= $this->renderStatementBlock($node, $body, true);
                }
                else {
                    $code .= $this->renderOpts->nl . $this->getIndentation() . $this->renderNode($body);
                }
                if ($this->requiresSemicolon($body)) {
                    $code .= ";";
                }
                break;
            case "JSXText":
            case "Literal":
            case "RegExpLiteral":
                $code .= $node->getRaw();
                break;
            case "JSXMemberExpression":
            case "MemberExpression":
                $property = $node->getProperty();
                $compiledProperty = $this->renderNode($property);
                $code .= $this->renderNode($node->getObject());
                $optional = false;
                if ($type === "MemberExpression") {
                    $optional = $node->getOptional();
                }
                $propertyType = $property->getType();
                if ($type === "MemberExpression" && ($node->getComputed() || $propertyType !== "Identifier" && $propertyType !== "PrivateIdentifier")) {
                    $code .= ($optional ? "?." : "") . "[" . $compiledProperty . "]";
                }
                else {
                    $code .= ($optional ? "?." : ".") . $compiledProperty;
                }
                break;
            case "MetaProperty":
                $code .= $node->getMeta() . "." . $node->getProperty();
                break;
            case "MethodDefinition":
                if ($node->getStatic()) {
                    $code .= "static ";
                }
                $value = $node->getValue();
                $key = $node->getKey();
                $kind = $node->getKind();
                if ($kind === $node::KIND_GET || $kind === $node::KIND_SET) {
                    $code .= $kind . " ";
                }
                else {
                    if ($value->getAsync()) {
                        $code .= "async ";
                    }
                    if ($value->getGenerator()) {
                        $code .= "*" . $this->renderOpts->sao;
                    }
                }
                if ($node->getComputed()) {
                    $code .= "[" . $this->renderNode($key) . "]";
                }
                else {
                    $code .= $this->renderNode($key);
                }
                $code .= $this->renderOpts->sao . preg_replace("/^[^(]+/", "", $this->renderNode($value));
                break;
            case "ObjectExpression":
                $currentIndentation = $this->getIndentation();
                $this->renderOpts->indLevel++;
                $indentation = $this->getIndentation();
                
                //Handle single line mode
                if (isset($this->renderOpts->forceSingleLine)) {
                    $start = $end = "";
                    $separator = "," . $this->renderOpts->sao;
                }
                else {
                    $end = $this->renderOpts->nl . $currentIndentation;
                    $start = $this->renderOpts->nl . $indentation;
                    $separator = "," . $this->renderOpts->nl . $indentation;
                }
                $code .= "{";
                $properties = $node->getProperties();
                if (count($properties)) {
                    $code .= $start . $this->joinNodes($properties, $separator) . $end;
                }
                $code .= "}";
                $this->renderOpts->indLevel--;
                break;
            case "ObjectPattern":
                $code .= "{" . $this->joinNodes($node->getProperties(), "," . $this->renderOpts->sao) . "}";
                break;
            case "ParenthesizedExpression":
                $code .= "(" . $this->renderOpts->sirb . $this->renderNode($node->getExpression()) . $this->renderOpts->sirb . ")";
                break;
            case "PrivateIdentifier":
                $code .= "#" . $node->getName();
                break;
            case "Property":
                $value = $node->getValue();
                $key = $node->getKey();
                $compiledKey = $this->renderNode($key);
                $compiledValue = $this->renderNode($value);
                $keyType = $key->getType();
                $valueType = $value->getType();
                if ($valueType === "AssignmentPattern" && $compiledKey === $this->renderNode($value->getLeft())) {
                    $code .= $compiledValue;
                }
                else {
                    $kind = $node->getKind();
                    $getterSetter = $kind === $node::KIND_GET || $kind === $node::KIND_SET;
                    if ($getterSetter) {
                        $code .= $kind . " ";
                    }
                    elseif ($value->getType() === "FunctionExpression" && $value->getGenerator()) {
                        $code .= "*" . $this->renderOpts->sao;
                    }
                    if ($node->getMethod() && $value->getAsync()) {
                        $code .= "async ";
                    }
                    if ($node->getComputed()) {
                        $code .= "[" . $compiledKey . "]";
                    }
                    else {
                        $code .= $compiledKey;
                    }
                    if ($node->getMethod() || $getterSetter) {
                        $code .= $this->renderOpts->sao . preg_replace("/^[^(]+/", "", $compiledValue);
                    }
                    elseif ($keyType !== "Identifier" || $valueType !== "Identifier" || $compiledKey !== $compiledValue) {
                        $code .= ($node->getShorthand() ? "=" : ":") . $this->renderOpts->sao . $compiledValue;
                    }
                }
                break;
            case "PropertyDefinition":
                if ($node->getStatic()) {
                    $code .= "static ";
                }
                $compiledKey = $this->renderNode($node->getKey());
                if ($node->getComputed()) {
                    $code .= "[" . $compiledKey . "]";
                }
                else {
                    $code .= $compiledKey;
                }
                if ($value = $node->getValue()) {
                    $code .= $this->renderOpts->sao . "=" . $this->renderOpts->sao . $this->renderNode($value);
                }
                break;
            case "RestElement":
            case "SpreadElement":
                $code .= "..." . $this->renderNode($node->getArgument());
                break;
            case "ReturnStatement":
                $code .= "return";
                if ($argument = $node->getArgument()) {
                    $code .= " " . $this->renderNode($argument);
                }
                break;
            case "SequenceExpression":
                $code .= $this->joinNodes($node->getExpressions(), "," . $this->renderOpts->sao);
                break;
            case "StaticBlock":
                $code .= "static";
                $code .= $this->renderStatementBlock($node, $node->getBody(), true);
                break;
            case "Super":
                $code .= "super";
                break;
            case "SwitchCase":
                if ($test = $node->getTest()) {
                    $code .= "case " . $this->renderNode($test);
                }
                else {
                    $code .= "default";
                }
                $code .= ":";
                if (count($node->getConsequent())) {
                    $code .= $this->renderStatementBlock($node, $node->getConsequent());
                }
                break;
            case "SwitchStatement":
                $code .= "switch" . $this->renderOpts->sao . "(" . $this->renderOpts->sirb . $this->renderNode($node->getDiscriminant()) . $this->renderOpts->sirb . ")" . $this->renderStatementBlock($node, $node->getCases(), true, false, false);
                break;
            case "TaggedTemplateExpression":
                $code .= $this->renderNode($node->getTag()) . $this->renderNode($node->getQuasi());
                break;
            case "TemplateElement":
                $code .= $node->getRawValue();
                break;
            case "TemplateLiteral":
                $code .= "`";
                foreach ($node->getParts() as $part) {
                    if ($part->getType() === "TemplateElement") {
                        $code .= $this->renderNode($part);
                    }
                    else {
                        $code .= "\$" . "{" . $this->renderNode($part) . "}";
                    }
                }
                $code .= "`";
                break;
            case "ThisExpression":
                $code .= "this";
                break;
            case "ThrowStatement":
                $code .= "throw " . $this->renderNode($node->getArgument());
                break;
            case "TryStatement":
                $code .= "try" . $this->renderStatementBlock($node, $node->getBlock(), true);
                if ($handler = $node->getHandler()) {
                    $code .= $this->renderOpts->sao . $this->renderNode($handler);
                }
                if ($finalizer = $node->getFinalizer()) {
                    $code .= $this->renderOpts->sao . "finally" . $this->renderStatementBlock($node, $finalizer, true);
                }
                break;
            case "UnaryExpression":
            case "UpdateExpression":
                $prefix = $node->getPrefix();
                if ($prefix) {
                    $code .= $node->getOperator();
                    if (preg_match("#^[a-z]+\$#i", $node->getOperator())) {
                        $code .= " ";
                    }
                }
                $code .= $this->renderNode($node->getArgument());
                if (!$prefix) {
                    $code .= $node->getOperator();
                }
                break;
            case "VariableDeclaration":
                $this->renderOpts->indLevel++;
                $indentation = $this->getIndentation();
                
                //Handle single line mode
                if (isset($this->renderOpts->forceSingleLine)) {
                    $separator = "," . $this->renderOpts->sao;
                }
                else {
                    $separator = "," . $this->renderOpts->nl . $indentation;
                }
                $code .= $node->getKind() . " " . $this->joinNodes($node->getDeclarations(), $separator);
                $this->renderOpts->indLevel--;
                break;
            case "VariableDeclarator":
                $code .= $this->renderNode($node->getId());
                if ($init = $node->getInit()) {
                    $code .= $this->renderOpts->sao . "=" . $this->renderOpts->sao . $this->renderNode($init);
                }
                break;
            case "WhileStatement":
                $code .= "while" . $this->renderOpts->sao . "(" . $this->renderOpts->sirb . $this->renderNode($node->getTest()) . $this->renderOpts->sirb . ")" . $this->renderStatementBlock($node, $node->getBody());
                break;
            case "WithStatement":
                $code .= "with" . $this->renderOpts->sao . "(" . $this->renderOpts->sirb . $this->renderNode($node->getObject()) . $this->renderOpts->sirb . ")" . $this->renderStatementBlock($node, $node->getBody());
                break;
            case "YieldExpression":
                $code .= "yield";
                if ($node->getDelegate()) {
                    $code .= " *";
                }
                if ($argument = $node->getArgument()) {
                    $code .= " " . $this->renderNode($argument);
                }
                break;
        }
        if ($addSemicolon) {
            $code .= ";";
        }
        if ($this->renderOpts->com) {
            $code .= $this->renderComments($node, false);
        }
        return $code;
    }
    
    /**
     * Renders a node as a block statement
     *
     * @param Syntax\Node\Node          $parent             Parent node
     * @param Syntax\Node\Node|array    $node               Node or array of 
     *                                                      nodes to render
     * @param bool                      $forceBrackets      Overrides brackets
     *                                                      inserting rules
     * @param bool                      $mandatorySeparator True if a starting
     *                                                      separator is
     *                                                      mandatory
     * @param bool                      $addSemicolons      Semicolons are
     *                                                      inserted automatically
     *                                                      if this parameter is
     *                                                      not false
     * @param bool                      $incIndent          If false indentation
     *                                                      level won't be
     *                                                      incremented
     * 
     * @return string
     */
    protected function renderStatementBlock($parent, $node, $forceBrackets = null, $mandatorySeparator = false, $addSemicolons = true, $incIndent = true) {
        $code = "";
        
        //If node is an array with only one element, handle it as a single node
        if (is_array($node) && count($node) === 1) {
            $node = $node[0];
        }
        
        //Special handling of BlockStatement and ClassBody nodes by rendering
        
        //their child nodes
        $origNode = null;
        if (!is_array($node) && in_array($node->getType(), array(
            "BlockStatement",
            "ClassBody",
        ))) {
            $origNode = $node;
            $node = $node->getBody();
        }
        
        //If $forceBrackets is not null use its value to override curly brackets
        
        //insertion rules
        if ($forceBrackets !== null) {
            $hasBrackets = $forceBrackets;
        }
        else {
            
            //Insert curly brackets if needed
            $hasBrackets = $this->needsBrackets($parent, $node);
        }
        $currentIndentation = $this->getIndentation();
        
        //If the node must be wrapped in curly braces a separator defined by formatter
        
        //must be inserted
        if ($hasBrackets) {
            if ($this->renderOpts->nlbc) {
                $code .= $this->renderOpts->nl . $currentIndentation;
            }
            else {
                $code .= $this->renderOpts->sao;
            }
        }
        elseif ($parent->getType() === "SwitchCase") {
            $code .= $this->renderOpts->nl;
        }
        $emptyBody = is_array($node) && !count($node);
        if ($this->renderOpts->com && $origNode) {
            $code .= $this->renderComments($origNode, true, !$emptyBody);
        }
        
        //Insert open curly bracket if required
        if ($hasBrackets) {
            $code .= "{" . $this->renderOpts->nl;
        }
        elseif ($mandatorySeparator) {
            
            //If bracket is not inserted but a separator is still required
            
            //a space is added
            $code .= " ";
        }
        
        //Increase indentation level
        if ($incIndent) {
            $this->renderOpts->indLevel++;
        }
        $subIndentation = $this->getIndentation();
        
        //Render the node or the array of nodes
        if (is_array($node)) {
            if (!$emptyBody) {
                $code .= $subIndentation . $this->joinNodes($node, $this->renderOpts->nl . $subIndentation, $addSemicolons);
            }
        }
        else {
            $code .= $subIndentation . $this->renderNode($node, $addSemicolons && $this->requiresSemicolon($node));
        }
        if ($this->renderOpts->com) {
            
            //Strip last new line and indentations added by comments rendering
            if (!$emptyBody) {
                $code = $this->trimEmptyLine($code);
            }
            if ($origNode) {
                $code .= $this->renderComments($origNode, false, !$emptyBody);
                if (!$emptyBody) {
                    $code = $this->trimEmptyLine($code);
                }
            }
        }
        
        //Reset the indentation level
        if ($incIndent) {
            $this->renderOpts->indLevel--;
        }
        
        //Insert closing curly bracket if required
        if ($hasBrackets) {
            
            //Add a new line if something was rendered
            if (!$emptyBody) {
                $code .= $this->renderOpts->nl;
            }
            $code .= $currentIndentation . "}";
        }
        return $code;
    }
    
    /**
     * Joins an array of nodes with the given separator
     * 
     * @param array     $nodes          Nodes
     * @param string    $separator      Separator
     * @param bool      $addSemicolons  True to add semicolons after each node
     * 
     * @return string
     */
    protected function joinNodes($nodes, $separator, $addSemicolons = false) {
        $parts = array();
        foreach ($nodes as $node) {
            if (!$node) {
                $code = "";
            }
            else {
                $code = $this->renderNode($node, $addSemicolons && $this->requiresSemicolon($node));
            }
            $parts[] = $code;
        }
        return implode($separator, $parts);
    }
    
    /**
     * Check if the node or the array of nodes need brackets to be rendered
     *
     * @param Syntax\Node\Node          $parent             Parent node
     * @param Syntax\Node\Node|array    $node               Node or array of
     *                                                      nodes to render
     * 
     * @return bool
     */
    protected function needsBrackets($parent, $node) {
        $parentType = $parent->getType();
        
        //The SwitchCase content needs brackets if it contains let or const declarations
        $inSwitchCase = $parentType === "SwitchCase";
        
        //Except for SwitchCase, brackets are needed if the formatter requires them or whenever
        
        //there are 0 or multiple nodes to render
        if (!$inSwitchCase && ($this->renderOpts->awb || is_array($node) && count($node) !== 1)) {
            return true;
        }
        if (!is_array($node)) {
            $node = array(
                $node,
            );
        }
        $addBrackets = false;
        $optBracketNodes = array(
            "DoWhileStatement",
            "ForInStatement",
            "ForOfStatement",
            "ForStatement",
            "WhileStatement",
            "WithStatement",
        );
        
        //An IfStatement requires brackets if it contains let or const declarations and if it has the "else" part
        
        //and contains another IfStatement with "else"
        $inIfWithElse = $parentType === "IfStatement" && $parent->getAlternate();
        $checkFn = function ($n) use ($inIfWithElse, $optBracketNodes, &$addBrackets) {
            $type = $n->getType();
            if ($inIfWithElse && $type === "IfStatement") {
                if (!$n->getAlternate()) {
                    $addBrackets = true;
                }
                return Traverser::DONT_TRAVERSE_CHILD_NODES;
            }
            elseif ($type === "BlockStatement") {
                if (count($n->getBody()) !== 1) {
                    return Traverser::DONT_TRAVERSE_CHILD_NODES;
                }
            }
            elseif ($inIfWithElse && $type === "LabeledStatement") {
                if ($n->getBody()
                    ->getType() === "BlockStatement") {
                    $addBrackets = true;
                }
                return Traverser::DONT_TRAVERSE_CHILD_NODES;
            }
            elseif ($type === "VariableDeclaration") {
                if (in_array($n->getKind(), array(
                    $n::KIND_LET,
                    $n::KIND_CONST,
                ))) {
                    $addBrackets = true;
                }
                return Traverser::DONT_TRAVERSE_CHILD_NODES;
            }
            elseif (!in_array($type, $optBracketNodes)) {
                return Traverser::DONT_TRAVERSE_CHILD_NODES;
            }
        };
        
        //Traverse every node but stop whenever the $addBrackets variable becomes true
        foreach ($node as $n) {
            $n->traverse($checkFn);
            if ($addBrackets) {
                break;
            }
        }
        return $addBrackets;
    }
    
    /**
     * Render node's comments
     * 
     * @param Syntax\Node\Node  $node             Node
     * @param bool              $leading          False to render trailing comments
     * @param bool|null         $blockContent     This paramater can have 3 values:
     *                                            - null: the node is not a block
     *                                            - false: the node is an empty block
     *                                            - true: the node is a block with content
     * 
     * @return string
     */
    protected function renderComments($node, $leading = true, $blockContent = null) {
        $code = "";
        $fn = $leading ? "getLeadingComments" : "getTrailingComments";
        $comments = $node ? $node->{$fn}() : array();
        $numComments = count($comments);
        if ($numComments) {
            $lastFormatted = $blockContent === false ? true : $leading;
            $refNode = $node;
            $refKey = $leading ? "end" : "start";
            $refNodeKey = $leading ? "start" : "end";
            $indent = $this->getIndentation();
            foreach ($comments as $k => $comment) {
                $lastComment = $k === $numComments - 1;
                $isMultilineComment = $comment->getKind() === Comment::KIND_MULTILINE;
                // Check if the comment must be formatted with new line and indentations
                $format = true;
                if ($refNode && $isMultilineComment && $comment->location && $refNode->location && $comment->location->{$refKey}
                    ->getLine() === $refNode->location->{$refNodeKey}
                    ->getLine()) {
                    $format = false;
                }
                
                //If the last comment wasn't formatted but this one must be formatted, add the new
                
                //line and the indentation
                if ($format && !$lastFormatted) {
                    $code .= $this->renderOpts->nl . $indent;
                }
                
                //Leading comments on empty blocks must render the initial indentation if format
                
                //is enabled
                if ($format && $blockContent === false && !$k) {
                    $code .= $indent;
                }
                $commentRaw = $comment->getRawText();
                
                //Reindent multiline comments if necessary
                if ($isMultilineComment && $indent && $this->renderOpts->rci) {
                    $commentRaw = preg_replace("/^\\s+\\*/m", $indent . " *", $commentRaw);
                }
                $code .= $commentRaw;
                
                //If format is enabled, add the new line character and the indentation if the node
                
                //is not an empty block or the it's not the last comment
                if ($format && ($blockContent !== true || !$lastComment || !$isMultilineComment)) {
                    
                    //For non multiline comments the new line is mandatory, even if the formatter
                    
                    //disables it
                    $code .= !$isMultilineComment && !$this->renderOpts->nl ? "\n" : $this->renderOpts->nl;
                    
                    //Last comment on blocks must not render indentation
                    if ($blockContent === null || !$lastComment) {
                        $code .= $indent;
                    }
                }
                $refNode = $comment;
                $lastFormatted = $format;
            }
        }
        return $code;
    }
    
    /**
     * Removes an empty line at the end of the given code, if present
     * 
     * @param string  $code   Code
     * 
     * @return string
     */
    protected function trimEmptyLine($code) {
        if ($this->renderOpts->nl) {
            $nl = preg_quote($this->renderOpts->nl, "/");
            $indent = preg_quote($this->getIndentation(), "/");
            $code = preg_replace("/{$nl}(?:{$indent})?\$/", "", $code);
        }
        return $code;
    }
    
    /**
     * Check if the given node requires semicolons insertion
     * 
     * @param Syntax\Node\Node  $node   Node
     * 
     * @return bool
     */
    protected function requiresSemicolon($node) {
        return !in_array($node->getType(), $this->noSemicolon);
    }
    
    /**
     * Returns the current indentation string
     * 
     * @return string
     */
    protected function getIndentation() {
        return str_repeat($this->renderOpts->ind, $this->renderOpts->indLevel);
    }

}

Members

Title Sort descending Modifiers Object type Summary
Renderer::$formatter protected property Formatter to use for the rendering
Renderer::$noSemicolon protected property Node types that does not require semicolon insertion
Renderer::$renderOpts protected property Rendering options taken from the formatter
Renderer::getFormatter public function Returns the formatter to use for the rendering
Renderer::getIndentation protected function Returns the current indentation string
Renderer::joinNodes protected function Joins an array of nodes with the given separator
Renderer::needsBrackets protected function Check if the node or the array of nodes need brackets to be rendered
Renderer::render public function Renders the given node
Renderer::renderComments protected function Render node&#039;s comments
Renderer::renderNode protected function Renders a node
Renderer::renderStatementBlock protected function Renders a node as a block statement
Renderer::requiresSemicolon protected function Check if the given node requires semicolons insertion
Renderer::setFormatter public function Sets the formatter to use for the rendering
Renderer::trimEmptyLine protected function Removes an empty line at the end of the given code, if present

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal