Skip to content

Commit da0da0f

Browse files
committed
Better align runtime context and errors with Handlebars.js
1 parent 3660d60 commit da0da0f

4 files changed

Lines changed: 51 additions & 30 deletions

File tree

src/Compiler.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,7 @@ public function composePHPRender(string $code): string
8989
\$cx = new RuntimeContext(
9090
helpers: isset(\$options['helpers']) ? array_merge(\$helpers, \$options['helpers']) : \$helpers,
9191
partials: isset(\$options['partials']) ? array_merge(\$partials, \$options['partials']) : \$partials,
92-
scopes: [],
93-
spVars: isset(\$options['data']) ? array_merge(['root' => \$in], \$options['data']) : ['root' => \$in],
94-
blParam: [],
95-
partialId: 0,
92+
data: isset(\$options['data']) ? array_merge(['root' => \$in], \$options['data']) : ['root' => \$in],
9693
);
9794
return '$code';
9895
};
@@ -904,7 +901,7 @@ private function compileProgramWithBlockParams(Program $program, array $bp, bool
904901
*/
905902
private function buildBasePath(bool $data, int $depth): string
906903
{
907-
$base = $data ? '$cx->spVars' : '$in';
904+
$base = $data ? '$cx->data' : '$in';
908905
if ($depth > 0) {
909906
$base = $data
910907
? $base . str_repeat("['_parent']", $depth)

src/Runtime.php

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ final class Runtime
1414
*/
1515
public static function miss(string $v): void
1616
{
17-
throw new \Exception("Runtime: $v does not exist");
17+
throw new \Exception('"' . $v . '" not defined');
1818
}
1919

2020
/**
@@ -159,14 +159,14 @@ public static function sec(RuntimeContext $cx, mixed $v, array $bp, mixed $in, b
159159
$cx->scopes[] = $in;
160160
}
161161
$i = 0;
162-
$oldSpvar = $cx->spVars ?? [];
163-
$cx->spVars = array_merge(['root' => $oldSpvar['root'] ?? null], $oldSpvar, ['_parent' => $oldSpvar]);
162+
$oldData = $cx->data ?? [];
163+
$cx->data = array_merge(['root' => $oldData['root'] ?? null], $oldData, ['_parent' => $oldData]);
164164

165165
foreach ($v as $index => $raw) {
166-
$cx->spVars['first'] = ($i === 0);
167-
$cx->spVars['last'] = ($i === $last);
168-
$cx->spVars['key'] = $index;
169-
$cx->spVars['index'] = $isSparseArray ? $index : $i;
166+
$cx->data['first'] = ($i === 0);
167+
$cx->data['last'] = ($i === $last);
168+
$cx->data['key'] = $index;
169+
$cx->data['index'] = $isSparseArray ? $index : $i;
170170
$i++;
171171
if ($bp) {
172172
$bpEntry = [];
@@ -187,11 +187,11 @@ public static function sec(RuntimeContext $cx, mixed $v, array $bp, mixed $in, b
187187
}
188188

189189
if ($isObj) {
190-
unset($cx->spVars['key']);
190+
unset($cx->data['key']);
191191
} else {
192-
unset($cx->spVars['last']);
192+
unset($cx->data['last']);
193193
}
194-
unset($cx->spVars['index'], $cx->spVars['first']);
194+
unset($cx->data['index'], $cx->data['first']);
195195

196196
if ($push) {
197197
array_pop($cx->scopes);
@@ -235,7 +235,7 @@ public static function sec(RuntimeContext $cx, mixed $v, array $bp, mixed $in, b
235235
},
236236
blockParams: 0,
237237
scope: $in,
238-
data: $cx->spVars,
238+
data: $cx->data,
239239
);
240240
$result = $v($options);
241241
return static::applyBlockHelperMissing($cx, $result, $in, $cb, $else);
@@ -387,7 +387,7 @@ public static function hbch(RuntimeContext $cx, string $ch, array $vars, mixed &
387387
inverse: fn() => '',
388388
blockParams: 0,
389389
scope: $_this,
390-
data: $cx->spVars,
390+
data: $cx->data,
391391
);
392392

393393
return static::exch($cx, $ch, $vars, $options);
@@ -407,7 +407,7 @@ public static function hbch(RuntimeContext $cx, string $ch, array $vars, mixed &
407407
public static function hbbch(RuntimeContext $cx, string $ch, array $vars, mixed &$_this, bool $inverted, \Closure $cb, ?\Closure $else = null, ?string $logicalName = null): mixed
408408
{
409409
$blockParams = isset($vars[2]) ? count($vars[2]) : 0;
410-
$data = &$cx->spVars;
410+
$data = &$cx->data;
411411

412412
// invert the logic
413413
if ($inverted) {
@@ -443,7 +443,7 @@ public static function dynhbbch(RuntimeContext $cx, string $name, mixed $callabl
443443
}
444444

445445
$blockParams = isset($vars[2]) ? count($vars[2]) : 0;
446-
$data = &$cx->spVars;
446+
$data = &$cx->data;
447447

448448
$options = new HelperOptions(
449449
name: '',
@@ -468,7 +468,7 @@ public static function dynhbbch(RuntimeContext $cx, string $name, mixed $callabl
468468

469469
/**
470470
* Build the $fn closure passed to HelperOptions for block helpers.
471-
* Handles spVars updates, block-param injection, and context scope pushing.
471+
* Handles private variable updates, block-param injection, and context scope pushing.
472472
*
473473
* @param array<array<mixed>> $vars
474474
*/
@@ -480,9 +480,9 @@ private static function makeBlockFn(RuntimeContext $cx, mixed $_this, ?\Closure
480480

481481
return function ($context = null, $data = null) use ($cx, $_this, $cb, $vars) {
482482
$cx = clone $cx;
483-
$old_spvar = $cx->spVars;
483+
$oldData = $cx->data;
484484
if (isset($data['data'])) {
485-
$cx->spVars = array_merge(['root' => $old_spvar['root']], $data['data'], ['_parent' => $old_spvar]);
485+
$cx->data = array_merge(['root' => $oldData['root']], $data['data'], ['_parent' => $oldData]);
486486
}
487487

488488
if (isset($data['blockParams'], $vars[2])) {
@@ -497,7 +497,7 @@ private static function makeBlockFn(RuntimeContext $cx, mixed $_this, ?\Closure
497497
}
498498

499499
if (isset($data['data'])) {
500-
$cx->spVars = $old_spvar;
500+
$cx->data = $oldData;
501501
}
502502
return $ret;
503503
};
@@ -554,7 +554,7 @@ public static function exch(RuntimeContext $cx, string $ch, array $vars, HelperO
554554
try {
555555
return ($cx->helpers[$ch])(...$args);
556556
} catch (\Throwable $e) {
557-
throw new \Exception("Runtime: call custom helper '$ch' error: " . $e->getMessage());
557+
throw new \Exception("Custom helper '$ch' error: " . $e->getMessage());
558558
}
559559
}
560560
}

src/RuntimeContext.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ class RuntimeContext
1111
* @param array<string, callable> $helpers
1212
* @param array<string, callable> $partials
1313
* @param array<mixed> $scopes
14-
* @param array<mixed> $spVars
14+
* @param array<mixed> $data
1515
* @param array<mixed> $blParam
1616
*/
1717
public function __construct(
1818
public array $helpers = [],
1919
public array $partials = [],
2020
public array $scopes = [],
21-
public array $spVars = [],
21+
public array $data = [],
2222
public array $blParam = [],
2323
public int $partialId = 0,
2424
) {}

tests/ErrorTest.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,44 @@ public static function renderErrorProvider(): array
4949
'template' => '{{> @partial-block}}',
5050
'expected' => "Runtime: the partial @partial-block could not be found",
5151
],
52+
[
53+
'template' => '{{foo.bar}}',
54+
'options' => new Options(strict: true),
55+
'data' => ['foo' => []],
56+
'expected' => '"foo.bar" not defined',
57+
],
5258
[
5359
'template' => '{{foo}}',
5460
'options' => new Options(strict: true),
55-
'expected' => 'Runtime: foo does not exist',
61+
'expected' => '"foo" not defined',
62+
],
63+
[
64+
// strict mode should override helperMissing
65+
'template' => '{{foo}}',
66+
'options' => new Options(
67+
strict: true,
68+
helpers: ['helperMissing' => fn() => 'bad'],
69+
),
70+
'expected' => '"foo" not defined',
71+
],
72+
[
73+
// strict mode should override blockHelperMissing
74+
'template' => '{{#foo}}OK{{/foo}}',
75+
'options' => new Options(
76+
strict: true,
77+
helpers: ['blockHelperMissing' => fn() => 'bad'],
78+
),
79+
'expected' => '"foo" not defined',
5680
],
5781
[
5882
'template' => '{{#foo}}OK{{/foo}}',
5983
'options' => new Options(strict: true),
60-
'expected' => 'Runtime: foo does not exist',
84+
'expected' => '"foo" not defined',
6185
],
6286
[
6387
'template' => '{{{foo}}}',
6488
'options' => new Options(strict: true),
65-
'expected' => 'Runtime: foo does not exist',
89+
'expected' => '"foo" not defined',
6690
],
6791
[
6892
'template' => '{{foo}}',
@@ -73,7 +97,7 @@ public static function renderErrorProvider(): array
7397
},
7498
],
7599
),
76-
'expected' => 'Runtime: call custom helper \'foo\' error: Expect the unexpected',
100+
'expected' => 'Custom helper \'foo\' error: Expect the unexpected',
77101
],
78102
// ensure that callable strings in data aren't treated as functions
79103
[

0 commit comments

Comments
 (0)