GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — v0.89-develop ( 8b9a0e...e02b63 )
by Zordius
02:44
created

Validator::section()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 9.4286
cc 2
eloc 4
nc 2
nop 3
crap 2
1
<?php
2
/*
3
4
Copyrights for code authored by Yahoo! Inc. is licensed under the following terms:
5
MIT License
6
Copyright (c) 2013-2015 Yahoo! Inc. All Rights Reserved.
7
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10
11
Origin: https://github.com/zordius/lightncandy
12
*/
13
14
/**
15
 * file to keep LightnCandy Validator
16
 *
17
 * @package    LightnCandy
18
 * @author     Zordius <[email protected]>
19
 */
20
21
namespace LightnCandy;
22
use \LightnCandy\Token;
23
use \LightnCandy\Parser;
24
use \LightnCandy\Partial;
25
use \LightnCandy\Expression;
26
use \LightnCandy\SafeString;
27
28
/**
29
 * LightnCandy Validator
30
 */
31
class Validator {
32
    /**
33
     * Verify template
34
     *
35
     * @param array<string,array|string|integer> $context Current context
36
     * @param string $template handlebars template
37
     */
38 630
    public static function verify(&$context, $template) {
39 630
        $template = SafeString::escapeTemplate(SafeString::stripExtendedComments($template));
40 630
        $context['level'] = 0;
41 630
        Parser::setDelimiter($context);
42
43 630
        while (preg_match($context['tokens']['search'], $template, $matches)) {
44
            // Skip a token when it is slash escaped
45 619
            if ($context['flags']['slash'] && ($matches[Token::POS_LSPACE] === '') && preg_match('/^(.*?)(\\\\+)$/s', $matches[Token::POS_LOTHER], $escmatch)) {
46 4
                if (strlen($escmatch[2]) % 4) {
47 2
                    static::pushToken($context, substr($matches[Token::POS_LOTHER], 0, -2) . $context['tokens']['startchar']);
48 2
                    $matches[Token::POS_BEGINTAG] = substr($matches[Token::POS_BEGINTAG], 1);
49 2
                    $template = implode('', array_slice($matches, Token::POS_BEGINTAG));
50 2
                    continue;
51
                } else {
52 2
                    $matches[Token::POS_LOTHER] = $escmatch[1] . str_repeat('\\', strlen($escmatch[2]) / 2);
53
                }
54 2
            }
55 617
            $context['tokens']['count']++;
56 617
            $V = static::token($matches, $context);
57 617
            static::pushToken($context, $matches[Token::POS_LOTHER]);
58 617
            static::pushToken($context, $matches[Token::POS_LSPACE]);
59 617
            if ($V) {
60 578
                if (is_array($V)) {
61 571
                    array_push($V, $matches, $context['tokens']['partialind']);
62 571
                }
63 578
                static::pushToken($context, $V);
64 578
            }
65 617
            $template = "{$matches[Token::POS_RSPACE]}{$matches[Token::POS_ROTHER]}";
66 617
        }
67 630
        static::pushToken($context, $template);
68
69 630
        if ($context['level'] > 0) {
70 6
            array_pop($context['stack']);
71 6
            array_pop($context['stack']);
72 6
            $token = array_pop($context['stack']);
73 6
            $context['error'][] = 'Unclosed token ' . ($context['rawblock'] ? "{{{{{$token}}}}}" : "{{#{$token}}}") . ' !!';
74 6
        }
75 630
    }
76
77
    /**
78
     * push a token into the stack when it is not empty string
79
     *
80
     * @param array<string,array|string|integer> $context Current context
81
     * @param string|array $token a parsed token or a string
82
     */
83 630
    protected static function pushToken(&$context, $token) {
84 630
        if ($token === '') {
85 575
            return;
86
        }
87 619
        if (is_string($token)) {
88 436
            if (is_string(end($context['parsed'][0]))) {
89 212
                $context['parsed'][0][key($context['parsed'][0])] .= $token;
90 212
                return;
91
            }
92 436
        }
93 619
        $context['parsed'][0][] = $token;
94 619
    }
95
96
    /**
97
     * push current token into the section stack
98
     *
99
     * @param array<string,array|string|integer> $context Current context
100
     * @param string $operation operation string
101
     * @param array<boolean|integer|string|array> $vars parsed arguments list
102
     */
103 297
    protected static function pushStack(&$context, $operation, $vars) {
104 297
        list($levels, $spvar, $var) = Expression::analyze($context, $vars[0]);
105 297
        $context['stack'][] = $context['currentToken'][Token::POS_INNERTAG];
106 297
        $context['stack'][] = Expression::toString($levels, $spvar, $var);
107 297
        $context['stack'][] = $operation;
108 297
        $context['level']++;
109 297
    }
110
111
    /**
112
     * Verify delimiters and operators
113
     *
114
     * @param string[] $token detected handlebars {{ }} token
115
     * @param array<string,array|string|integer> $context current compile context
116
     *
117
     * @return boolean|null Return true when invalid
118
     *
119
     * @expect null when input array_fill(0, 11, ''), array()
120
     * @expect null when input array(0, 0, 0, 0, 0, '{{', '#', '...', '}}'), array()
121
     * @expect true when input array(0, 0, 0, 0, 0, '{', '#', '...', '}'), array()
122
     */
123 618
    protected static function delimiter($token, &$context) {
124
        // {{ }}} or {{{ }} are invalid
1 ignored issue
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
125 618
        if (strlen($token[Token::POS_BEGINRAW]) !== strlen($token[Token::POS_ENDRAW])) {
126 6
            $context['error'][] = 'Bad token ' . Token::toString($token) . ' ! Do you mean ' . Token::toString($token, array(Token::POS_BEGINRAW => '', Token::POS_ENDRAW => '')) . ' or ' . Token::toString($token, array(Token::POS_BEGINRAW => '{', Token::POS_ENDRAW => '}')) . '?';
127 6
            return true;
128
        }
129
        // {{{# }}} or {{{! }}} or {{{/ }}} or {{{^ }}} are invalid.
130 612
        if ((strlen($token[Token::POS_BEGINRAW]) == 1) && $token[Token::POS_OP] && ($token[Token::POS_OP] !== '&')) {
131 5
            $context['error'][] = 'Bad token ' . Token::toString($token) . ' ! Do you mean ' . Token::toString($token, array(Token::POS_BEGINRAW => '', Token::POS_ENDRAW => '')) . ' ?';
132 5
            return true;
133
        }
134 608
    }
135
136
    /**
137
     * Verify operators
138
     *
139
     * @param string $operator the operator string
140
     * @param array<string,array|string|integer> $context current compile context
141
     * @param array<boolean|integer|string|array> $vars parsed arguments list
142
     *
143
     * @return boolean|integer|null Return true when invalid or detected
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double|boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
144
     *
145
     * @expect null when input '', array(), array()
146
     * @expect 2 when input '^', array('usedFeature' => array('isec' => 1), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0)), array(array('foo'))
147
     * @expect true when input '/', array('stack' => array('[with]', '#'), 'level' => 1, 'currentToken' => array(0,0,0,0,0,0,0,'with'), 'flags' => array('nohbh' => 0)), array(array())
148
     * @expect 4 when input '#', array('usedFeature' => array('sec' => 3), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0)), array(array('x'))
149
     * @expect 5 when input '#', array('usedFeature' => array('if' => 4), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0, 'nohbh' => 0)), array(array('if'))
150
     * @expect 6 when input '#', array('usedFeature' => array('with' => 5), 'level' => 0, 'flags' => array('nohbh' => 0, 'runpart' => 0, 'spvar' => 0), 'currentToken' => array(0,0,0,0,0,0,0,0)), array(array('with'))
151
     * @expect 7 when input '#', array('usedFeature' => array('each' => 6), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0, 'nohbh' => 0)), array(array('each'))
152
     * @expect 8 when input '#', array('usedFeature' => array('unless' => 7), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0, 'nohbh' => 0)), array(array('unless'))
153
     * @expect 9 when input '#', array('blockhelpers' => array('abc' => ''), 'usedFeature' => array('bhelper' => 8), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0)), array(array('abc'))
154
     * @expect 11 when input '#', array('hbhelpers' => array('abc' => ''), 'usedFeature' => array('hbhelper' => 10), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0)), array(array('abc'))
155
     * @expect true when input '>', array('basedir' => array('.'), 'fileext' => array('.tmpl'), 'usedFeature' => array('partial' => 7), 'level' => 0, 'flags' => array('skippartial' => 0, 'runpart' => 0, 'spvar' => 0), 'currentToken' => array(0,0,0,0,0,0,0,0)), array('test')
156
     */
157 579
    protected static function operator($operator, &$context, &$vars) {
158
        switch ($operator) {
159 579
            case '>':
160 68
                return static::partial($context, $vars);
161
162 556
            case '^':
163 63
                if (!isset($vars[0][0])) {
164 22
                    if (!$context['flags']['else']) {
165 1
                        $context['error'][] = 'Do not support {{^}}, you should do compile with LightnCandy::FLAG_ELSE flag';
166 1
                        return;
167
                    } else {
168 21
                        return static::doElse($context);
169
                    }
170
                }
171
172 41
                if (static::isBlockHelper($context, $vars)) {
173 3
                    static::pushStack($context, '#', $vars);
174 3
                    return static::blockCustomHelper($context, $vars, true);
175
                }
176
177 38
                static::pushStack($context, '^', $vars);
178 38
                return static::invertedSection($context, $vars);
179
180 556
            case '/':
181 293
                $r = static::blockEnd($context, $vars);
182 293
                array_pop($context['stack']);
183 293
                array_pop($context['stack']);
184 293
                array_pop($context['stack']);
185 293
                return $r;
186
187 532
            case '#':
188 267
                static::pushStack($context, '#', $vars);
189
190 267
                if (static::isBlockHelper($context, $vars)) {
191 50
                    return static::blockCustomHelper($context, $vars);
192
                }
193
194 224
                return static::blockBegin($context, $vars);
195
        }
196 444
    }
197
198
    /**
199
     * validate block begin token
200
     *
201
     * @param array<string,array|string|integer> $context current compile context
202
     * @param array<boolean|integer|string|array> $vars parsed arguments list
203
     *
204
     * @return boolean Return true always
205
     */
206 223
    protected static function blockBegin(&$context, $vars) {
207 223
        switch (isset($vars[0][0]) ? $vars[0][0] : null) {
208 223
            case 'with':
209 19
                return static::with($context, $vars);
210 208
            case 'each':
211 50
                return static::section($context, $vars, true);
212 168
            case 'unless':
213 5
                return static::unless($context, $vars, true);
0 ignored issues
show
Unused Code introduced by
The call to Validator::unless() has too many arguments starting with true.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
214 163
            case 'if':
215 59
                return static::doIf($context, $vars, true);
0 ignored issues
show
Unused Code introduced by
The call to Validator::doIf() has too many arguments starting with true.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
216 105
            default:
217 105
                $context['usedFeature']['sec']++;
218 105
                return true;
219 105
        }
220
    }
221
222
    /**
223
     * validate builtin helpers
224
     *
225
     * @param array<string,array|string|integer> $context current compile context
226
     * @param array<boolean|integer|string|array> $vars parsed arguments list
227
     */
228 119
    protected static function builtin(&$context, $vars) {
229 119
        if ($context['flags']['nohbh']) {
230 8
            if (isset($vars[1][0])) {
231 4
                $context['error'][] = "Do not support {{#{$vars[0][0]} var}} because you compile with LightnCandy::FLAG_NOHBHELPERS flag";
232 4
            }
233 8
        } else {
234 111
            if (count($vars) < 2) {
235 5
                $context['error'][] = "No argument after {{#{$vars[0][0]}}} !";
236 5
            }
237
        }
238 119
        $context['usedFeature'][$vars[0][0]]++;
239 119
    }
240
241
    /**
242
     * validate section token
243
     *
244
     * @param array<string,array|string|integer> $context current compile context
245
     * @param array<boolean|integer|string|array> $vars parsed arguments list
246
     * @param boolean $isEach the section is #each
247
     *
248
     * @return boolean Return true always
249
     */
250 50
    protected static function section(&$context, $vars, $isEach = false) {
251 50
        if ($isEach) {
252 50
            static::builtin($context, $vars);
253 50
        }
254 50
        return true;
255
    }
256
257
    /**
258
     * validate with token
259
     *
260
     * @param array<string,array|string|integer> $context current compile context
261
     * @param array<boolean|integer|string|array> $vars parsed arguments list
262
     *
263
     * @return boolean Return true always
264
     */
265 19
    protected static function with(&$context, $vars) {
266 19
        static::builtin($context, $vars);
267 19
        return true;
268
    }
269
270
    /**
271
     * validate unless token
272
     *
273
     * @param array<string,array|string|integer> $context current compile context
274
     * @param array<boolean|integer|string|array> $vars parsed arguments list
275
     *
276
     * @return boolean Return true always
277
     */
278 5
    protected static function unless(&$context, $vars) {
279 5
        static::builtin($context, $vars);
280 5
        return true;
281
    }
282
283
    /**
284
     * validate if token
285
     *
286
     * @param array<string,array|string|integer> $context current compile context
287
     * @param array<boolean|integer|string|array> $vars parsed arguments list
288
     *
289
     * @return boolean Return true always
290
     */
291 59
    protected static function doIf(&$context, $vars) {
292 59
        static::builtin($context, $vars);
293 59
        return true;
294
    }
295
296
    /**
297
     * validate block custom helper token
298
     *
299
     * @param array<string,array|string|integer> $context current compile context
300
     * @param array<boolean|integer|string|array> $vars parsed arguments list
301
     * @param boolean $inverted the logic will be inverted
302
     *
303
     * @return string|null Return compiled code segment for the token
1 ignored issue
show
Documentation introduced by
Should the return type not be integer|double|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
304
     */
305 52
    protected static function blockCustomHelper(&$context, $vars, $inverted = false) {
306 52
        if (is_string($vars[0][0])) {
307
            // detect handlebars custom helpers.
308 52
            if (isset($context['hbhelpers'][$vars[0][0]])) {
309 49
                return ++$context['usedFeature']['hbhelper'];
310
            }
311
312
            // detect block custom helpers.
313 3
            if (isset($context['blockhelpers'][$vars[0][0]])) {
314 3
                return ++$context['usedFeature']['bhelper'];
315
            }
316
        }
317
    }
318
319
    /**
320
     * validate inverted section
321
     *
322
     * @param array<string,array|string|integer> $context current compile context
323
     * @param array<boolean|integer|string|array> $vars parsed arguments list
324
     *
325
     * @return integer Return number of inverted sections
1 ignored issue
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
326
     */
327 37
    protected static function invertedSection(&$context, $vars) {
328 37
        return ++$context['usedFeature']['isec'];
329
    }
330
331
    /**
332
     * Return compiled PHP code for a handlebars block end token
333
     *
334
     * @param array<string,array|string|integer> $context current compile context
335
     * @param array<boolean|integer|string|array> $vars parsed arguments list
336
     *
337
     * @return boolean Return true
338
     */
339 292
    protected static function blockEnd(&$context, $vars) {
340 292
        $context['level']--;
341 292
        $c = count($context['stack']) - 2;
342 292
        $pop = ($c >= 0) ? $context['stack'][$c + 1] : '';
343 292
        $pop2 = ($c >= 0) ? $context['stack'][$c]: '';
344 292
        switch ($context['currentToken'][Token::POS_INNERTAG]) {
345 292
            case 'with':
346 19
                if (!$context['flags']['nohbh']) {
347 17
                    if ($pop2 !== '[with]') {
348 1
                        $context['error'][] = 'Unexpect token: {{/with}} !';
349 1
                        return;
350
                    }
351 16
                }
352 18
                return true;
353 279
        }
354
355
        switch($pop) {
356 279
            case '#':
357 279
            case '^':
358 278
                list($levels, $spvar, $var) = Expression::analyze($context, $vars[0]);
359 278
                $v = Expression::toString($levels, $spvar, $var);
360 278
                if ($pop2 !== $v) {
361 1
                    $context['error'][] = 'Unexpect token ' . Token::toString($context['currentToken']) . " ! Previous token {{{$pop}$pop2}} is not closed";
362 1
                    return;
363
                }
364 277
                if ($pop == '^') {
365 37
                    return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
366
                }
367 248
                return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
368 1
            default:
369 1
                $context['error'][] = 'Unexpect token: ' . Token::toString($context['currentToken']) . ' !';
370 1
                return;
371 1
        }
372
    }
373
374
    /**
375
     * handle delimiter change
376
     *
377
     * @param array<string,array|string|integer> $context current compile context
378
     *
379
     * @return boolean|null Return true when delimiter changed
380
     */
381 607
    protected static function isDelimiter(&$context) {
382 607
        if (preg_match('/^=\s*([^ ]+)\s+([^ ]+)\s*=$/', $context['currentToken'][Token::POS_INNERTAG], $matched)) {
383 15
            $context['usedFeature']['delimiter']++;
384 15
            Parser::setDelimiter($context, $matched[1], $matched[2]);
385 15
            return true;
386
        }
387 598
    }
388
389
    /**
390
     * handle raw block
391
     *
392
     * @param string[] $token detected handlebars {{ }} token
393
     * @param array<string,array|string|integer> $context current compile context
394
     *
395
     * @return boolean|null Return true when in rawblock mode
396
     */
397 617
    protected static function rawblock(&$token, &$context) {
398 617
        $inner = $token[Token::POS_INNERTAG];
399 617
        trim($inner);
400
401
        // skip parse when inside raw block
402 617
        if ($context['rawblock'] && !(($token[Token::POS_BEGINRAW] === '{{') && ($token[Token::POS_OP] === '/') && ($context['rawblock'] === $inner))) {
403 4
            return true;
404
        }
405
406 617
        $token[Token::POS_INNERTAG] = $inner;
407
408
        // Handle raw block
409 617
        if ($token[Token::POS_BEGINRAW] === '{{') {
410 7
            if ($token[Token::POS_ENDRAW] !== '}}') {
411 1
                $context['error'][] = 'Bad token ' . Token::toString($token) . ' ! Do you mean ' . Token::toString($token, array(Token::POS_ENDRAW => '}}')) . ' ?';
412 1
            }
413 7
            if ($context['rawblock']) {
414 4
                Parser::setDelimiter($context);
415 4
                $context['rawblock'] = false;
416 4
            } else {
417 7
                if ($token[Token::POS_OP]) {
418 1
                    $context['error'][] = "Wrong raw block begin with " . Token::toString($token) . ' ! Remove "' . $token[Token::POS_OP] . '" to fix this issue.';
419 1
                }
420 7
                $context['rawblock'] = $token[Token::POS_INNERTAG];
421 7
                Parser::setDelimiter($context);
422 7
                $token[Token::POS_OP] = '#';
423
            }
424 7
            $token[Token::POS_ENDRAW] = '}}';
425 7
        }
426 617
    }
427
428
    /**
429
     * handle comment
430
     *
431
     * @param string[] $token detected handlebars {{ }} token
432
     * @param array<string,array|string|integer> $context current compile context
433
     *
434
     * @return boolean|null Return true when is comment
435
     */
436 598
    protected static function comment(&$token, &$context) {
437 598
        if ($token[Token::POS_OP] === '!') {
438 25
            $context['usedFeature']['comment']++;
439 25
            return true;
440
        }
441 578
    }
442
443
    /**
444
     * Collect handlebars usage information, detect template error.
445
     *
446
     * @param string[] $token detected handlebars {{ }} token
447
     * @param array<string,array|string|integer> $context current compile context
448
     */
449 617
    protected static function token(&$token, &$context) {
450 617
        $context['currentToken'] = $token;
451 617
        if (static::rawblock($token, $context)) {
452 4
            return Token::toString($token);
453
        }
454
455 617
        if (static::delimiter($token, $context)) {
456 10
            return;
457
        }
458
459 607
        if (static::isDelimiter($context)) {
460 15
            static::spacing($token, $context);
461 15
            return;
462
        }
463
464 598
        if (static::comment($token, $context)) {
465 25
            static::spacing($token, $context);
466 25
            return;
467
        }
468
469 578
        list($raw, $vars) = Parser::parse($token, $context);
470
471
        // Handle spacing (standalone tags, partial indent)
472 578
        static::spacing($token, $context, (($token[Token::POS_OP] === '') || ($token[Token::POS_OP] === '&')) && (!$context['flags']['else'] || !isset($vars[0][0]) || ($vars[0][0] !== 'else')));
473
474 578
        if (static::operator($token[Token::POS_OP], $context, $vars)) {
475 342
            return array($raw, $vars);
476
        }
477
478 446
        if (count($vars) == 0) {
479 6
            return $context['error'][] = 'Wrong variable naming in ' . Token::toString($token);
480
        }
481
482 440
        if (!isset($vars[0])) {
483 1
            return $context['error'][] = 'Do not support name=value in ' . Token::toString($token) . ', you should use it after a custom helper.';
484
        }
485
486 439
        $context['usedFeature'][$raw ? 'raw' : 'enc']++;
487
488 439
        foreach ($vars as $var) {
489 439
            if (!isset($var[0])) {
490 56
                if ($context['level'] == 0) {
491 17
                    $context['usedFeature']['rootthis']++;
492 17
                }
493 56
                $context['usedFeature']['this']++;
494 56
            }
495 439
        }
496
497 439
        if (!isset($vars[0][0])) {
498 48
            return array($raw, $vars);
499
        }
500
501 408
        if (!static::helper($context, $vars[0][0])) {
502 313
            static::lookup($context, $vars);
503 313
        }
504
505 408
        return array($raw, $vars);
506
    }
507
508
    /**
509
     * Return 1 or larger number when else token detected
510
     *
511
     * @param array<string,array|string|integer> $context current compile context
512
     *
513
     * @return integer Return 1 or larger number when else token detected
1 ignored issue
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
514
     */
515 21
    protected static function doElse(&$context) {
516 21
        if ($context['level'] == 0) {
517
            $context['error'][] = '{{else}} only valid in if, unless, each, and #section context';
518
        }
519 21
        return ++$context['usedFeature']['else'];
520
    }
521
522
    /**
523
     * Return true whe the name is listed in helper table
524
     *
525
     * @param array<string,array|string|integer> $context current compile context
526
     * @param string $name token name
0 ignored issues
show
Bug introduced by
There is no parameter named $name. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
527
     *
528
     * @return boolean Return true when it is custom helper
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
529
     */
530 313
    public static function lookup(&$context, $vars) {
531 313
        if (isset($vars[0][0]) && $vars[0][0] == 'lookup') {
532 3
            if (!$context['flags']['nohbh']) {
533 3
                if (count($vars) < 2) {
534
                    $context['error'][] = "No argument after {{lookup}} !";
535 3
                } else if (count($vars) < 3) {
536
                    $context['error'][] = "{{lookup}} requires 2 arguments !";
537
                }
538 3
                $context['usedFeature']['lookup']++;
539 3
                return true;
540
            }
541
        }
542 310
    }
543
544
    /**
545
     * Return true when the name is listed in helper table
546
     *
547
     * @param array<string,array|string|integer> $context current compile context
548
     * @param string $name token name
549
     *
550
     * @return boolean Return true when it is custom helper
551
     */
552 416
    public static function helper(&$context, $name) {
553 416
        if (isset($context['hbhelpers'][$name])) {
554 86
            $context['usedFeature']['hbhelper']++;
555 86
            return true;
556
        }
557
558 336
        if (isset($context['helpers'][$name])) {
559 23
            $context['usedFeature']['helper']++;
560 23
            return true;
561
        }
562
563 315
        return false;
564
    }
565
566
    /**
567
     * detect for block custom helper
568
     *
569
     * @param array<string,array|string|integer> $context current compile context
570
     * @param array<boolean|integer|string|array> $vars parsed arguments list
571
     *
572
     * @return boolean|null Return true when this token is block custom helper
573
     */
574 297
    protected static function isBlockHelper($context, $vars) {
575 297
        if (!isset($vars[0][0])) {
576 4
            return;
577
        }
578
579 294
        if (!isset($context['blockhelpers'][$vars[0][0]]) && !isset($context['hbhelpers'][$vars[0][0]])) {
580 248
            return;
581
        }
582
583 52
        return true;
584
    }
585
586
    /**
587
     * validate partial
588
     *
589
     * @param array<string,array|string|integer> $context current compile context
590
     * @param array<boolean|integer|string|array> $vars parsed arguments list
591
     *
592
     * @return integer|true Return 1 or larger number for runtime partial, return true for other case
1 ignored issue
show
Documentation introduced by
Should the return type not be integer|double|boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
593
     */
594 67
    protected static function partial(&$context, $vars) {
595 67
        if (Parser::isSubexp($vars[0])) {
596 5
            if ($context['flags']['runpart']) {
597 4
                return $context['usedFeature']['dynpartial']++;
598
            } else {
599 1
                $context['error'][] = "You use dynamic partial name as '{$vars[0][2]}', this only works with option FLAG_RUNTIMEPARTIAL enabled";
600 1
                return true;
601
            }
602
        } else {
603 62
            Partial::readPartial($vars[0][0], $context);
604
        }
605 62
        if (!$context['flags']['runpart']) {
606 9
        $named = count(array_diff_key($vars, array_keys(array_keys($vars)))) > 0;
607 9
            if ($named || (count($vars) > 1)) {
608 1
                $context['error'][] = "Do not support {{>{$context['currentToken'][Token::POS_INNERTAG]}}}, you should do compile with LightnCandy::FLAG_RUNTIMEPARTIAL flag";
609 1
            }
610 9
        }
611
612 62
        return true;
613
    }
614
615
    /**
616
     * Modify $token when spacing rules matched.
617
     *
618
     * @param array<string> $token detected handlebars {{ }} token
619
     * @param array<string,array|string|integer> $context current compile context
620
     * @param boolean $nost do not do stand alone logic
621
     *
622
     * @return string|null Return compiled code segment for the token
623
     */
624 607
    protected static function spacing(&$token, &$context, $nost = false) {
625
        // left line change detection
626 607
        $lsp = preg_match('/^(.*)(\\r?\\n)([ \\t]*?)$/s', $token[Token::POS_LSPACE], $lmatch);
627 607
        $ind = $lsp ? $lmatch[3] : $token[Token::POS_LSPACE];
628
        // right line change detection
629 607
        $rsp = preg_match('/^([ \\t]*?)(\\r?\\n)(.*)$/s', $token[Token::POS_RSPACE], $rmatch);
630 607
        $st = true;
631
        // setup ahead flag
632 607
        $ahead = $context['tokens']['ahead'];
633 607
        $context['tokens']['ahead'] = preg_match('/^[^\n]*{{/s', $token[Token::POS_RSPACE] . $token[Token::POS_ROTHER]);
634
        // reset partial indent
635 607
        $context['tokens']['partialind'] = '';
636
        // same tags in the same line , not standalone
637 607
        if (!$lsp && $ahead) {
638 290
            $st = false;
639 290
        }
640 607
        if ($nost) {
641 435
            $st = false;
642 435
        }
643
        // not standalone because other things in the same line ahead
644 607
        if ($token[Token::POS_LOTHER] && !$token[Token::POS_LSPACE]) {
645 184
            $st = false;
646 184
        }
647
        // not standalone because other things in the same line behind
648 607
        if ($token[Token::POS_ROTHER] && !$token[Token::POS_RSPACE]) {
649 286
            $st = false;
650 286
        }
651 607
        if ($st && (($lsp && $rsp) // both side cr
652 118
            || ($rsp && !$token[Token::POS_LOTHER]) // first line without left
653 118
            || ($lsp && !$token[Token::POS_ROTHER]) // final line
654 607
           )) {
655
            // handle partial
656 63
            if ($token[Token::POS_OP] === '>') {
657 15
                if (!$context['flags']['noind']) {
658 10
                    $context['tokens']['partialind'] = $token[Token::POS_LSPACECTL] ? '' : $ind;
659 10
                    $token[Token::POS_LSPACE] = (isset($lmatch[2]) ? ($lmatch[1] . $lmatch[2]) : '');
660 10
                }
661 15
            } else {
662 52
                $token[Token::POS_LSPACE] = (isset($lmatch[2]) ? ($lmatch[1] . $lmatch[2]) : '');
663
            }
664 63
            $token[Token::POS_RSPACE] = isset($rmatch[3]) ? $rmatch[3] : '';
665 63
        }
666
667
        // Handle space control.
668 607
        if ($token[Token::POS_LSPACECTL]) {
669 30
            $token[Token::POS_LSPACE] = '';
670 30
        }
671 607
        if ($token[Token::POS_RSPACECTL]) {
672 33
            $token[Token::POS_RSPACE] = '';
673 33
        }
674 607
    }
675
}
676
677