Skip to content

Commit bbb7441

Browse files
committed
Fix used helper context
1 parent 475dfc6 commit bbb7441

File tree

4 files changed

+48
-30
lines changed

4 files changed

+48
-30
lines changed

src/Handlebars.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace DevTheorem\Handlebars;
44

5+
use DevTheorem\HandlebarsParser\ParserFactory;
6+
57
final class Handlebars
68
{
79
protected static Context $lastContext;
@@ -17,6 +19,15 @@ public static function compile(string $template, Options $options = new Options(
1719
return self::template(self::precompile($template, $options));
1820
}
1921

22+
/**
23+
* Compiles a template so it can be executed immediately.
24+
* @return \Closure(mixed=, array<mixed>=):string
25+
*/
26+
public static function compile_new(string $template, Options $options = new Options()): \Closure
27+
{
28+
return self::template(self::precompile_new($template, $options));
29+
}
30+
2031
/**
2132
* Precompiles a handlebars template into PHP code which can be executed later.
2233
*/
@@ -31,6 +42,17 @@ public static function precompile(string $template, Options $options = new Optio
3142
return Compiler::composePHPRender($context, $code);
3243
}
3344

45+
public static function precompile_new(string $template, Options $options = new Options()): string
46+
{
47+
$context = new Context($options);
48+
$parser = (new ParserFactory())->create();
49+
$program = $parser->parse($template);
50+
$code = (new NewCompiler())->compile($program, $context);
51+
52+
// return full PHP render code as string
53+
return Compiler::composePHPRender($context, $code);
54+
}
55+
3456
/**
3557
* Sets up a template that was precompiled with precompile().
3658
*/

src/NewCompiler.php

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use DevTheorem\HandlebarsParser\Ast\Decorator;
1010
use DevTheorem\HandlebarsParser\Ast\Expression as AstExpression;
1111
use DevTheorem\HandlebarsParser\Ast\Hash;
12+
use DevTheorem\HandlebarsParser\Ast\Literal;
1213
use DevTheorem\HandlebarsParser\Ast\MustacheStatement;
1314
use DevTheorem\HandlebarsParser\Ast\Node;
1415
use DevTheorem\HandlebarsParser\Ast\NullLiteral;
@@ -27,22 +28,21 @@
2728
final class NewCompiler
2829
{
2930
private int $partialBlockId = 0;
31+
private Context $context;
32+
private Options $options;
3033

3134
/**
3235
* @param list<array<string>> $blockParamValues
33-
* @param list<Node> $sourceNode
3436
*/
3537
public function __construct(
3638
private array $blockParamValues = [],
37-
private array $sourceNode = [],
38-
private Options $options = new Options(),
3939
) {}
4040

41-
public function compile(Program $program, Options $options): string
41+
public function compile(Program $program, Context $context): string
4242
{
4343
$this->blockParamValues = [];
44-
$this->sourceNode = [];
45-
$this->options = $options;
44+
$this->context = $context;
45+
$this->options = $context->options;
4646
$this->partialBlockId = 0;
4747

4848
array_unshift($this->blockParamValues, $program->blockParams);
@@ -241,6 +241,7 @@ private function compileBlockHelper(BlockStatement $block, string $helperName):
241241
}
242242

243243
$params = $this->compileParams($block->params, $block->hash, $bp ?: null);
244+
$this->context->usedHelpers[$helperName] = true;
244245

245246
if ($inverted) {
246247
$body = $block->inverse ? $this->compileProgram($block->inverse) : "''";
@@ -257,7 +258,12 @@ private function compileBlockHelper(BlockStatement $block, string $helperName):
257258

258259
private function DecoratorBlock(): string
259260
{
260-
return '';
261+
return ''; // todo: throw?
262+
}
263+
264+
private function Decorator(Decorator $decorator): string
265+
{
266+
return ''; // todo: throw?
261267
}
262268

263269
private function PartialStatement(PartialStatement $statement): string
@@ -312,6 +318,7 @@ private function MustacheStatement(MustacheStatement $mustache): string
312318

313319
// Registered helper
314320
if ($helperName !== null && isset($this->options->helpers[$helperName])) {
321+
$this->context->usedHelpers[$helperName] = true;
315322
$params = $this->compileParams($mustache->params, $mustache->hash);
316323
$call = "LR::hbch(\$cx, '$helperName', $params, \$in)";
317324
return "'." . $this->getFuncName($fn, $call) . ").'";
@@ -337,11 +344,6 @@ private function MustacheStatement(MustacheStatement $mustache): string
337344
return "'." . $this->getFuncName($fn, $val) . ").'";
338345
}
339346

340-
private function Decorator(Decorator $decorator): string
341-
{
342-
return '';
343-
}
344-
345347
private function ContentStatement(ContentStatement $statement): string
346348
{
347349
return addcslashes($statement->value, "'\\");
@@ -365,6 +367,7 @@ private function SubExpression(SubExpression $expression): string
365367

366368
// Registered helper
367369
if ($helperName !== null && isset($this->options->helpers[$helperName])) {
370+
$this->context->usedHelpers[$helperName] = true;
368371
$params = $this->compileParams($expression->params, $expression->hash);
369372
return "LR::hbch(\$cx, '$helperName', $params, \$in)";
370373
}
@@ -376,6 +379,7 @@ private function SubExpression(SubExpression $expression): string
376379

377380
// Non-registered helper — still try as helper call
378381
if ($helperName !== null) {
382+
$this->context->usedHelpers[$helperName] = true;
379383
$params = $this->compileParams($expression->params, $expression->hash);
380384
return "LR::hbch(\$cx, '$helperName', $params, \$in)";
381385
}
@@ -530,7 +534,7 @@ private function compilePartialParams(array $params, ?Hash $hash): string
530534
/**
531535
* Extract simple helper name from a path if it's a single-segment, non-data, depth-0 path.
532536
*/
533-
private function getSimpleHelperName(PathExpression|\DevTheorem\HandlebarsParser\Ast\Literal $path): ?string
537+
private function getSimpleHelperName(PathExpression|Literal $path): ?string
534538
{
535539
if (!$path instanceof PathExpression) {
536540
return null;

test_compare.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@
2929

3030
$pass = 0;
3131
$fail = 0;
32+
$newCompiler = new NewCompiler();
3233

3334
foreach ($tests as $t) {
3435
$program = $parser->parse($t);
35-
$new = (new NewCompiler())->compile($program, $opts);
36+
$new = $newCompiler->compile($program, $opts);
3637

3738
$ctx = new Context($opts);
3839
$old = Compiler::compileTemplate($ctx, $t);

tests/ErrorTest.php

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,9 @@
1313
*/
1414
class ErrorTest extends TestCase
1515
{
16-
public function testException(): void
17-
{
18-
try {
19-
$php = Handlebars::precompile('{{{foo}}');
20-
} catch (\Exception $E) {
21-
$this->assertEquals('Bad token {{{foo}} ! Do you mean {{foo}} or {{{foo}}}?', $E->getMessage());
22-
}
23-
}
24-
2516
public function testLog(): void
2617
{
27-
$template = Handlebars::compile('{{log foo}}');
18+
$template = Handlebars::compile_new('{{log foo}}');
2819

2920
date_default_timezone_set('GMT');
3021
$tmpDir = sys_get_temp_dir();
@@ -49,13 +40,13 @@ public function testLog(): void
4940
#[DataProvider("renderErrorProvider")]
5041
public function testRenderingException(array $test): void
5142
{
52-
$php = Handlebars::precompile($test['template'], $test['options'] ?? new Options());
43+
$php = Handlebars::precompile_new($test['template'], $test['options'] ?? new Options());
5344
$renderer = Handlebars::template($php);
5445
try {
5546
$renderer(null);
5647
$this->fail("Expected to throw exception: {$test['expected']}. CODE: $php");
57-
} catch (\Exception $E) {
58-
$this->assertEquals($test['expected'], $E->getMessage());
48+
} catch (\Exception $e) {
49+
$this->assertEquals($test['expected'], $e->getMessage(), $php);
5950
}
6051
}
6152

@@ -82,17 +73,17 @@ public static function renderErrorProvider(): array
8273
[
8374
'template' => '{{foo}}',
8475
'options' => new Options(strict: true),
85-
'expected' => 'Runtime: [foo] does not exist',
76+
'expected' => 'Runtime: foo does not exist',
8677
],
8778
[
8879
'template' => '{{#foo}}OK{{/foo}}',
8980
'options' => new Options(strict: true),
90-
'expected' => 'Runtime: [foo] does not exist',
81+
'expected' => 'Runtime: foo does not exist',
9182
],
9283
[
9384
'template' => '{{{foo}}}',
9485
'options' => new Options(strict: true),
95-
'expected' => 'Runtime: [foo] does not exist',
86+
'expected' => 'Runtime: foo does not exist',
9687
],
9788
[
9889
'template' => '{{foo}}',

0 commit comments

Comments
 (0)