{"action":"opened","issue":{"url":"https://api.github.com/repos/zordius/lightncandy/issues/295","repository_url":"https://api.github.com/repos/zordius/lightncandy","labels_url":"https://api.github.com/repos/zordius/lightncandy/issues/295/labels{/name}","comments_url":"https://api.github.com/repos/zordius/lightncandy/issues/295/comments","events_url":"https://api.github.com/repos/zordius/lightncandy/issues/295/events","html_url":"https://github.com/zordius/lightncandy/issues/295","id":318043477,"number":295,"title":"Template Parsing Error — PHP Fatal error: Uncaught Exception: Unexcepted ')'","user":{"login":"jasonh-brimar","id":6097460,"avatar_url":"https://avatars0.githubusercontent.com/u/6097460?v=4","gravatar_id":"","url":"https://api.github.com/users/jasonh-brimar","html_url":"https://github.com/jasonh-brimar","followers_url":"https://api.github.com/users/jasonh-brimar/followers","following_url":"https://api.github.com/users/jasonh-brimar/following{/other_user}","gists_url":"https://api.github.com/users/jasonh-brimar/gists{/gist_id}","starred_url":"https://api.github.com/users/jasonh-brimar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jasonh-brimar/subscriptions","organizations_url":"https://api.github.com/users/jasonh-brimar/orgs","repos_url":"https://api.github.com/users/jasonh-brimar/repos","events_url":"https://api.github.com/users/jasonh-brimar/events{/privacy}","received_events_url":"https://api.github.com/users/jasonh-brimar/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-04-26T14:01:04Z","updated_at":"2018-04-26T14:01:04Z","closed_at":null,"author_association":"NONE","body":"The PHP Code:\r\n-------------\r\n\r\n```php\r\nrequire('./vendor/autoload.php');\r\n\r\n// Define the template string.\r\n// $templateString = '{{> MyPartial (newObject name=\"John Doe\") message=(echo message=\"Hello World!\")}}'; // This template works.\r\n// $templateString = '{{> MyPartial (newObject name=\"JohnDoe\") message=(echo message=(echo message=\"Hello World!\"))}}'; // This template works.\r\n$templateString = '{{> MyPartial (newObject name=\"John Doe\") message=(echo message=(echo message=\"Hello World!\"))}}'; // This template does NOT work.\r\n\r\n// Define the partial template string.\r\n$partialTemplateString = '{{name}} says: “{{message}}”';\r\n\r\n// Define helpers...\r\n$helpers = [\r\n    'newObject' => (\r\n        function ($options): stdClass\r\n        {\r\n            return (object)$options['hash'];\r\n        }\r\n    ),\r\n    'echo' => (\r\n        function ($options)\r\n        {\r\n            return $options['hash']['message'];\r\n        }\r\n    )\r\n];\r\n\r\n// Define the LightnCandy compile options.\r\n$compileOptions = [\r\n    'flags' => LightnCandy\\LightnCandy::FLAG_HANDLEBARSJS_FULL | LightnCandy\\LightnCandy::FLAG_ERROR_SKIPPARTIAL | LightnCandy\\LightnCandy::FLAG_EXTHELPER | LightnCandy\\LightnCandy::FLAG_ERROR_EXCEPTION,\r\n    'helperresolver' => (\r\n        function ($context, $name) use ($helpers): bool\r\n        {\r\n            return array_key_exists($name, $helpers);\r\n        }\r\n    )\r\n];\r\n\r\n// Create the template using LightnCandy.\r\n$template = eval(LightnCandy\\LightnCandy::compile($templateString, $compileOptions));\r\n\r\n// Define the LightnCandy render options.\r\n$renderOptions = [\r\n    'partials' => [\r\n        'MyPartial' => eval('use \\LightnCandy\\Runtime as LR; use \\LightnCandy\\SafeString as SafeString; return ' . LightnCandy\\LightnCandy::compilePartial($partialTemplateString, $compileOptions) . ';')\r\n    ],\r\n    'helpers' => $helpers\r\n];\r\n\r\n?>\r\n<!doctype html>\r\n<html lang=\"en\">\r\n\r\n    <head>\r\n        <meta charset=\"utf-8\">\r\n        <title>Nested Helper Error Test</title>\r\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\r\n        <style>\r\n            #php, #js {\r\n                border: 1px solid black;\r\n                margin: 20px;\r\n                padding: 20px;\r\n            }\r\n            #php {\r\n                background: #ffe;\r\n            }\r\n            #js {\r\n                background: #eff;\r\n            }\r\n        </style>\r\n    </head>\r\n\r\n    <body>\r\n\r\n        <div id=\"php\">\r\n            <h1>Rendered by PHP</h1>\r\n            <div id=\"render-php\"><?= $template(new stdClass(), $renderOptions) ?></div>\r\n        </div>\r\n\r\n        <div id=\"js\">\r\n            <h1>Rendered by JS</h1>\r\n            <div id=\"render-js\"></div>\r\n        </div>\r\n\r\n        <script id=\"template\" type=\"text/x-handlebars-template\"><?= $templateString ?></script>\r\n        <script id=\"partial-template\" type=\"text/x-handlebars-template\"><?= $partialTemplateString ?></script>\r\n\r\n        <script src=\"https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.js\" integrity=\"sha256-JWyJjSicZs/EX4AJmuCHSYYARSvIkYeM79Dn1pJOSCE=\" crossorigin=\"anonymous\"></script>\r\n\r\n        <script>\r\n\r\n            // Register helpers.\r\n            Handlebars.registerHelper({\r\n                newObject: function (options) {\r\n                    return Object.assign({}, options.hash);\r\n                },\r\n                echo: function (options) {\r\n                    return options.hash.message;\r\n                }\r\n            });\r\n\r\n            // Make the partial template available as a partial.\r\n            Handlebars.registerPartial(\"MyPartial\", Handlebars.compile(document.getElementById(\"partial-template\").innerHTML));\r\n\r\n            // Compile the the template and render.\r\n            document.getElementById(\"render-js\").innerHTML = Handlebars.compile(document.getElementById(\"template\").innerHTML)({});\r\n\r\n        </script>\r\n\r\n    </body>\r\n\r\n</html>\r\n```\r\n\r\nThe Issue:\r\n----------\r\n\r\nLightnCandy fails to parse/compile the template above. It seems to be related to the combination of both the space in `\"John Doe\"` and the double-nested usage of the `echo` helper. If either the space is removed or the helper is reduced to a single level of nesting, no error is thrown (as shown in the two alternative `$templateString` values shared above).\r\n\r\nBelow is the stack trace sent to my error log:\r\n\r\n```\r\nmod_fcgid: stderr: PHP Fatal error:  Uncaught Exception: Unexcepted ')' in expression ' MyPartial (newObject name=\"John Doe\") message=(echo message=(echo message=\"Hello World!\"))' !! in vendor/zordius/lightncandy/src/LightnCandy.php:110\r\nmod_fcgid: stderr: Stack trace:\r\nmod_fcgid: stderr: #0 vendor/zordius/lightncandy/src/LightnCandy.php(54): LightnCandy\\\\LightnCandy::handleError(Array)\r\nmod_fcgid: stderr: #1 test.php(42): LightnCandy\\\\LightnCandy::compile('{{> MyPartial (...', Array)\r\nmod_fcgid: stderr: #2 {main}\r\nmod_fcgid: stderr:   thrown in vendor/zordius/lightncandy/src/LightnCandy.php on line 110\r\n```\r\n\r\nNote that even when using one of the working `$templateString` alternatives shared above, LightnCandy’s output won’t match that of Handlebars. Both the name (John Doe) and the message (Hello World!) will be missing. I created separate issues for the specific causes of both of those absent values (#293 and #294)."}}
{"actor":{"display_login":"jasonh-brimar"}}