Vous êtes connecté en tant que anonymous Se Deconnecter
Browse code

Application modulaire fonctionnelle !

Emmanuel ROY authored on 12/08/2019 15:10:25
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,557 +0,0 @@
1
-<?php
2
-
3
-namespace Illuminate\View\Compilers;
4
-
5
-use Illuminate\Support\Arr;
6
-use Illuminate\Support\Str;
7
-use InvalidArgumentException;
8
-
9
-class BladeCompiler extends Compiler implements CompilerInterface
10
-{
11
-    use Concerns\CompilesAuthorizations,
12
-        Concerns\CompilesComments,
13
-        Concerns\CompilesComponents,
14
-        Concerns\CompilesConditionals,
15
-        Concerns\CompilesEchos,
16
-        Concerns\CompilesErrors,
17
-        Concerns\CompilesHelpers,
18
-        Concerns\CompilesIncludes,
19
-        Concerns\CompilesInjections,
20
-        Concerns\CompilesJson,
21
-        Concerns\CompilesLayouts,
22
-        Concerns\CompilesLoops,
23
-        Concerns\CompilesRawPhp,
24
-        Concerns\CompilesStacks,
25
-        Concerns\CompilesTranslations;
26
-
27
-    /**
28
-     * All of the registered extensions.
29
-     *
30
-     * @var array
31
-     */
32
-    protected $extensions = [];
33
-
34
-    /**
35
-     * All custom "directive" handlers.
36
-     *
37
-     * @var array
38
-     */
39
-    protected $customDirectives = [];
40
-
41
-    /**
42
-     * All custom "condition" handlers.
43
-     *
44
-     * @var array
45
-     */
46
-    protected $conditions = [];
47
-
48
-    /**
49
-     * The file currently being compiled.
50
-     *
51
-     * @var string
52
-     */
53
-    protected $path;
54
-
55
-    /**
56
-     * All of the available compiler functions.
57
-     *
58
-     * @var array
59
-     */
60
-    protected $compilers = [
61
-        'Comments',
62
-        'Extensions',
63
-        'Statements',
64
-        'Echos',
65
-    ];
66
-
67
-    /**
68
-     * Array of opening and closing tags for raw echos.
69
-     *
70
-     * @var array
71
-     */
72
-    protected $rawTags = ['{!!', '!!}'];
73
-
74
-    /**
75
-     * Array of opening and closing tags for regular echos.
76
-     *
77
-     * @var array
78
-     */
79
-    protected $contentTags = ['{{', '}}'];
80
-
81
-    /**
82
-     * Array of opening and closing tags for escaped echos.
83
-     *
84
-     * @var array
85
-     */
86
-    protected $escapedTags = ['{{{', '}}}'];
87
-
88
-    /**
89
-     * The "regular" / legacy echo string format.
90
-     *
91
-     * @var string
92
-     */
93
-    protected $echoFormat = 'e(%s)';
94
-
95
-    /**
96
-     * Array of footer lines to be added to template.
97
-     *
98
-     * @var array
99
-     */
100
-    protected $footer = [];
101
-
102
-    /**
103
-     * Array to temporary store the raw blocks found in the template.
104
-     *
105
-     * @var array
106
-     */
107
-    protected $rawBlocks = [];
108
-
109
-    /**
110
-     * Compile the view at the given path.
111
-     *
112
-     * @param  string|null  $path
113
-     * @return void
114
-     */
115
-    public function compile($path = null)
116
-    {
117
-        if ($path) {
118
-            $this->setPath($path);
119
-        }
120
-
121
-        if (! is_null($this->cachePath)) {
122
-            $contents = $this->compileString(
123
-                $this->files->get($this->getPath())
124
-            );
125
-
126
-            if (! empty($this->getPath())) {
127
-                $tokens = $this->getOpenAndClosingPhpTokens($contents);
128
-
129
-                // If the tokens we retrieved from the compiled contents have at least
130
-                // one opening tag and if that last token isn't the closing tag, we
131
-                // need to close the statement before adding the path at the end.
132
-                if ($tokens->isNotEmpty() && $tokens->last() !== T_CLOSE_TAG) {
133
-                    $contents .= ' ?>';
134
-                }
135
-
136
-                $contents .= "<?php /**PATH {$this->getPath()} ENDPATH**/ ?>";
137
-            }
138
-
139
-            $this->files->put(
140
-                $this->getCompiledPath($this->getPath()), $contents
141
-            );
142
-        }
143
-    }
144
-
145
-    /**
146
-     * Get the open and closing PHP tag tokens from the given string.
147
-     *
148
-     * @param  string  $contents
149
-     * @return \Illuminate\Support\Collection
150
-     */
151
-    protected function getOpenAndClosingPhpTokens($contents)
152
-    {
153
-        return collect(token_get_all($contents))
154
-            ->pluck($tokenNumber = 0)
155
-            ->filter(function ($token) {
156
-                return in_array($token, [T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG]);
157
-            });
158
-    }
159
-
160
-    /**
161
-     * Get the path currently being compiled.
162
-     *
163
-     * @return string
164
-     */
165
-    public function getPath()
166
-    {
167
-        return $this->path;
168
-    }
169
-
170
-    /**
171
-     * Set the path currently being compiled.
172
-     *
173
-     * @param  string  $path
174
-     * @return void
175
-     */
176
-    public function setPath($path)
177
-    {
178
-        $this->path = $path;
179
-    }
180
-
181
-    /**
182
-     * Compile the given Blade template contents.
183
-     *
184
-     * @param  string  $value
185
-     * @return string
186
-     */
187
-    public function compileString($value)
188
-    {
189
-        if (strpos($value, '@verbatim') !== false) {
190
-            $value = $this->storeVerbatimBlocks($value);
191
-        }
192
-
193
-        $this->footer = [];
194
-
195
-        if (strpos($value, '@php') !== false) {
196
-            $value = $this->storePhpBlocks($value);
197
-        }
198
-
199
-        $result = '';
200
-
201
-        // Here we will loop through all of the tokens returned by the Zend lexer and
202
-        // parse each one into the corresponding valid PHP. We will then have this
203
-        // template as the correctly rendered PHP that can be rendered natively.
204
-        foreach (token_get_all($value) as $token) {
205
-            $result .= is_array($token) ? $this->parseToken($token) : $token;
206
-        }
207
-
208
-        if (! empty($this->rawBlocks)) {
209
-            $result = $this->restoreRawContent($result);
210
-        }
211
-
212
-        // If there are any footer lines that need to get added to a template we will
213
-        // add them here at the end of the template. This gets used mainly for the
214
-        // template inheritance via the extends keyword that should be appended.
215
-        if (count($this->footer) > 0) {
216
-            $result = $this->addFooters($result);
217
-        }
218
-
219
-        return $result;
220
-    }
221
-
222
-    /**
223
-     * Store the verbatim blocks and replace them with a temporary placeholder.
224
-     *
225
-     * @param  string  $value
226
-     * @return string
227
-     */
228
-    protected function storeVerbatimBlocks($value)
229
-    {
230
-        return preg_replace_callback('/(?<!@)@verbatim(.*?)@endverbatim/s', function ($matches) {
231
-            return $this->storeRawBlock($matches[1]);
232
-        }, $value);
233
-    }
234
-
235
-    /**
236
-     * Store the PHP blocks and replace them with a temporary placeholder.
237
-     *
238
-     * @param  string  $value
239
-     * @return string
240
-     */
241
-    protected function storePhpBlocks($value)
242
-    {
243
-        return preg_replace_callback('/(?<!@)@php(.*?)@endphp/s', function ($matches) {
244
-            return $this->storeRawBlock("<?php{$matches[1]}?>");
245
-        }, $value);
246
-    }
247
-
248
-    /**
249
-     * Store a raw block and return a unique raw placeholder.
250
-     *
251
-     * @param  string  $value
252
-     * @return string
253
-     */
254
-    protected function storeRawBlock($value)
255
-    {
256
-        return $this->getRawPlaceholder(
257
-            array_push($this->rawBlocks, $value) - 1
258
-        );
259
-    }
260
-
261
-    /**
262
-     * Replace the raw placeholders with the original code stored in the raw blocks.
263
-     *
264
-     * @param  string  $result
265
-     * @return string
266
-     */
267
-    protected function restoreRawContent($result)
268
-    {
269
-        $result = preg_replace_callback('/'.$this->getRawPlaceholder('(\d+)').'/', function ($matches) {
270
-            return $this->rawBlocks[$matches[1]];
271
-        }, $result);
272
-
273
-        $this->rawBlocks = [];
274
-
275
-        return $result;
276
-    }
277
-
278
-    /**
279
-     * Get a placeholder to temporary mark the position of raw blocks.
280
-     *
281
-     * @param  int|string  $replace
282
-     * @return string
283
-     */
284
-    protected function getRawPlaceholder($replace)
285
-    {
286
-        return str_replace('#', $replace, '@__raw_block_#__@');
287
-    }
288
-
289
-    /**
290
-     * Add the stored footers onto the given content.
291
-     *
292
-     * @param  string  $result
293
-     * @return string
294
-     */
295
-    protected function addFooters($result)
296
-    {
297
-        return ltrim($result, PHP_EOL)
298
-                .PHP_EOL.implode(PHP_EOL, array_reverse($this->footer));
299
-    }
300
-
301
-    /**
302
-     * Parse the tokens from the template.
303
-     *
304
-     * @param  array  $token
305
-     * @return string
306
-     */
307
-    protected function parseToken($token)
308
-    {
309
-        [$id, $content] = $token;
310
-
311
-        if ($id == T_INLINE_HTML) {
312
-            foreach ($this->compilers as $type) {
313
-                $content = $this->{"compile{$type}"}($content);
314
-            }
315
-        }
316
-
317
-        return $content;
318
-    }
319
-
320
-    /**
321
-     * Execute the user defined extensions.
322
-     *
323
-     * @param  string  $value
324
-     * @return string
325
-     */
326
-    protected function compileExtensions($value)
327
-    {
328
-        foreach ($this->extensions as $compiler) {
329
-            $value = call_user_func($compiler, $value, $this);
330
-        }
331
-
332
-        return $value;
333
-    }
334
-
335
-    /**
336
-     * Compile Blade statements that start with "@".
337
-     *
338
-     * @param  string  $value
339
-     * @return string
340
-     */
341
-    protected function compileStatements($value)
342
-    {
343
-        return preg_replace_callback(
344
-            '/\B@(@?\w+(?:::\w+)?)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x', function ($match) {
345
-                return $this->compileStatement($match);
346
-            }, $value
347
-        );
348
-    }
349
-
350
-    /**
351
-     * Compile a single Blade @ statement.
352
-     *
353
-     * @param  array  $match
354
-     * @return string
355
-     */
356
-    protected function compileStatement($match)
357
-    {
358
-        if (Str::contains($match[1], '@')) {
359
-            $match[0] = isset($match[3]) ? $match[1].$match[3] : $match[1];
360
-        } elseif (isset($this->customDirectives[$match[1]])) {
361
-            $match[0] = $this->callCustomDirective($match[1], Arr::get($match, 3));
362
-        } elseif (method_exists($this, $method = 'compile'.ucfirst($match[1]))) {
363
-            $match[0] = $this->$method(Arr::get($match, 3));
364
-        }
365
-
366
-        return isset($match[3]) ? $match[0] : $match[0].$match[2];
367
-    }
368
-
369
-    /**
370
-     * Call the given directive with the given value.
371
-     *
372
-     * @param  string  $name
373
-     * @param  string|null  $value
374
-     * @return string
375
-     */
376
-    protected function callCustomDirective($name, $value)
377
-    {
378
-        if (Str::startsWith($value, '(') && Str::endsWith($value, ')')) {
379
-            $value = Str::substr($value, 1, -1);
380
-        }
381
-
382
-        return call_user_func($this->customDirectives[$name], trim($value));
383
-    }
384
-
385
-    /**
386
-     * Strip the parentheses from the given expression.
387
-     *
388
-     * @param  string  $expression
389
-     * @return string
390
-     */
391
-    public function stripParentheses($expression)
392
-    {
393
-        if (Str::startsWith($expression, '(')) {
394
-            $expression = substr($expression, 1, -1);
395
-        }
396
-
397
-        return $expression;
398
-    }
399
-
400
-    /**
401
-     * Register a custom Blade compiler.
402
-     *
403
-     * @param  callable  $compiler
404
-     * @return void
405
-     */
406
-    public function extend(callable $compiler)
407
-    {
408
-        $this->extensions[] = $compiler;
409
-    }
410
-
411
-    /**
412
-     * Get the extensions used by the compiler.
413
-     *
414
-     * @return array
415
-     */
416
-    public function getExtensions()
417
-    {
418
-        return $this->extensions;
419
-    }
420
-
421
-    /**
422
-     * Register an "if" statement directive.
423
-     *
424
-     * @param  string  $name
425
-     * @param  callable  $callback
426
-     * @return void
427
-     */
428
-    public function if($name, callable $callback)
429
-    {
430
-        $this->conditions[$name] = $callback;
431
-
432
-        $this->directive($name, function ($expression) use ($name) {
433
-            return $expression !== ''
434
-                    ? "<?php if (\Illuminate\Support\Facades\Blade::check('{$name}', {$expression})): ?>"
435
-                    : "<?php if (\Illuminate\Support\Facades\Blade::check('{$name}')): ?>";
436
-        });
437
-
438
-        $this->directive('else'.$name, function ($expression) use ($name) {
439
-            return $expression !== ''
440
-                ? "<?php elseif (\Illuminate\Support\Facades\Blade::check('{$name}', {$expression})): ?>"
441
-                : "<?php elseif (\Illuminate\Support\Facades\Blade::check('{$name}')): ?>";
442
-        });
443
-
444
-        $this->directive('end'.$name, function () {
445
-            return '<?php endif; ?>';
446
-        });
447
-    }
448
-
449
-    /**
450
-     * Check the result of a condition.
451
-     *
452
-     * @param  string  $name
453
-     * @param  array  $parameters
454
-     * @return bool
455
-     */
456
-    public function check($name, ...$parameters)
457
-    {
458
-        return call_user_func($this->conditions[$name], ...$parameters);
459
-    }
460
-
461
-    /**
462
-     * Register a component alias directive.
463
-     *
464
-     * @param  string  $path
465
-     * @param  string|null  $alias
466
-     * @return void
467
-     */
468
-    public function component($path, $alias = null)
469
-    {
470
-        $alias = $alias ?: Arr::last(explode('.', $path));
471
-
472
-        $this->directive($alias, function ($expression) use ($path) {
473
-            return $expression
474
-                        ? "<?php \$__env->startComponent('{$path}', {$expression}); ?>"
475
-                        : "<?php \$__env->startComponent('{$path}'); ?>";
476
-        });
477
-
478
-        $this->directive('end'.$alias, function ($expression) {
479
-            return '<?php echo $__env->renderComponent(); ?>';
480
-        });
481
-    }
482
-
483
-    /**
484
-     * Register an include alias directive.
485
-     *
486
-     * @param  string  $path
487
-     * @param  string|null  $alias
488
-     * @return void
489
-     */
490
-    public function include($path, $alias = null)
491
-    {
492
-        $alias = $alias ?: Arr::last(explode('.', $path));
493
-
494
-        $this->directive($alias, function ($expression) use ($path) {
495
-            $expression = $this->stripParentheses($expression) ?: '[]';
496
-
497
-            return "<?php echo \$__env->make('{$path}', {$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>";
498
-        });
499
-    }
500
-
501
-    /**
502
-     * Register a handler for custom directives.
503
-     *
504
-     * @param  string  $name
505
-     * @param  callable  $handler
506
-     * @return void
507
-     */
508
-    public function directive($name, callable $handler)
509
-    {
510
-        if (! preg_match('/^\w+(?:::\w+)?$/x', $name)) {
511
-            throw new InvalidArgumentException("The directive name [{$name}] is not valid. Directive names must only contain alphanumeric characters and underscores.");
512
-        }
513
-
514
-        $this->customDirectives[$name] = $handler;
515
-    }
516
-
517
-    /**
518
-     * Get the list of custom directives.
519
-     *
520
-     * @return array
521
-     */
522
-    public function getCustomDirectives()
523
-    {
524
-        return $this->customDirectives;
525
-    }
526
-
527
-    /**
528
-     * Set the echo format to be used by the compiler.
529
-     *
530
-     * @param  string  $format
531
-     * @return void
532
-     */
533
-    public function setEchoFormat($format)
534
-    {
535
-        $this->echoFormat = $format;
536
-    }
537
-
538
-    /**
539
-     * Set the "echo" format to double encode entities.
540
-     *
541
-     * @return void
542
-     */
543
-    public function withDoubleEncoding()
544
-    {
545
-        $this->setEchoFormat('e(%s, true)');
546
-    }
547
-
548
-    /**
549
-     * Set the "echo" format to not double encode entities.
550
-     *
551
-     * @return void
552
-     */
553
-    public function withoutDoubleEncoding()
554
-    {
555
-        $this->setEchoFormat('e(%s, false)');
556
-    }
557
-}
Browse code

initial commit

Emmanuel ROY authored on 09/08/2019 08:39:02
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,557 @@
1
+<?php
2
+
3
+namespace Illuminate\View\Compilers;
4
+
5
+use Illuminate\Support\Arr;
6
+use Illuminate\Support\Str;
7
+use InvalidArgumentException;
8
+
9
+class BladeCompiler extends Compiler implements CompilerInterface
10
+{
11
+    use Concerns\CompilesAuthorizations,
12
+        Concerns\CompilesComments,
13
+        Concerns\CompilesComponents,
14
+        Concerns\CompilesConditionals,
15
+        Concerns\CompilesEchos,
16
+        Concerns\CompilesErrors,
17
+        Concerns\CompilesHelpers,
18
+        Concerns\CompilesIncludes,
19
+        Concerns\CompilesInjections,
20
+        Concerns\CompilesJson,
21
+        Concerns\CompilesLayouts,
22
+        Concerns\CompilesLoops,
23
+        Concerns\CompilesRawPhp,
24
+        Concerns\CompilesStacks,
25
+        Concerns\CompilesTranslations;
26
+
27
+    /**
28
+     * All of the registered extensions.
29
+     *
30
+     * @var array
31
+     */
32
+    protected $extensions = [];
33
+
34
+    /**
35
+     * All custom "directive" handlers.
36
+     *
37
+     * @var array
38
+     */
39
+    protected $customDirectives = [];
40
+
41
+    /**
42
+     * All custom "condition" handlers.
43
+     *
44
+     * @var array
45
+     */
46
+    protected $conditions = [];
47
+
48
+    /**
49
+     * The file currently being compiled.
50
+     *
51
+     * @var string
52
+     */
53
+    protected $path;
54
+
55
+    /**
56
+     * All of the available compiler functions.
57
+     *
58
+     * @var array
59
+     */
60
+    protected $compilers = [
61
+        'Comments',
62
+        'Extensions',
63
+        'Statements',
64
+        'Echos',
65
+    ];
66
+
67
+    /**
68
+     * Array of opening and closing tags for raw echos.
69
+     *
70
+     * @var array
71
+     */
72
+    protected $rawTags = ['{!!', '!!}'];
73
+
74
+    /**
75
+     * Array of opening and closing tags for regular echos.
76
+     *
77
+     * @var array
78
+     */
79
+    protected $contentTags = ['{{', '}}'];
80
+
81
+    /**
82
+     * Array of opening and closing tags for escaped echos.
83
+     *
84
+     * @var array
85
+     */
86
+    protected $escapedTags = ['{{{', '}}}'];
87
+
88
+    /**
89
+     * The "regular" / legacy echo string format.
90
+     *
91
+     * @var string
92
+     */
93
+    protected $echoFormat = 'e(%s)';
94
+
95
+    /**
96
+     * Array of footer lines to be added to template.
97
+     *
98
+     * @var array
99
+     */
100
+    protected $footer = [];
101
+
102
+    /**
103
+     * Array to temporary store the raw blocks found in the template.
104
+     *
105
+     * @var array
106
+     */
107
+    protected $rawBlocks = [];
108
+
109
+    /**
110
+     * Compile the view at the given path.
111
+     *
112
+     * @param  string|null  $path
113
+     * @return void
114
+     */
115
+    public function compile($path = null)
116
+    {
117
+        if ($path) {
118
+            $this->setPath($path);
119
+        }
120
+
121
+        if (! is_null($this->cachePath)) {
122
+            $contents = $this->compileString(
123
+                $this->files->get($this->getPath())
124
+            );
125
+
126
+            if (! empty($this->getPath())) {
127
+                $tokens = $this->getOpenAndClosingPhpTokens($contents);
128
+
129
+                // If the tokens we retrieved from the compiled contents have at least
130
+                // one opening tag and if that last token isn't the closing tag, we
131
+                // need to close the statement before adding the path at the end.
132
+                if ($tokens->isNotEmpty() && $tokens->last() !== T_CLOSE_TAG) {
133
+                    $contents .= ' ?>';
134
+                }
135
+
136
+                $contents .= "<?php /**PATH {$this->getPath()} ENDPATH**/ ?>";
137
+            }
138
+
139
+            $this->files->put(
140
+                $this->getCompiledPath($this->getPath()), $contents
141
+            );
142
+        }
143
+    }
144
+
145
+    /**
146
+     * Get the open and closing PHP tag tokens from the given string.
147
+     *
148
+     * @param  string  $contents
149
+     * @return \Illuminate\Support\Collection
150
+     */
151
+    protected function getOpenAndClosingPhpTokens($contents)
152
+    {
153
+        return collect(token_get_all($contents))
154
+            ->pluck($tokenNumber = 0)
155
+            ->filter(function ($token) {
156
+                return in_array($token, [T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG]);
157
+            });
158
+    }
159
+
160
+    /**
161
+     * Get the path currently being compiled.
162
+     *
163
+     * @return string
164
+     */
165
+    public function getPath()
166
+    {
167
+        return $this->path;
168
+    }
169
+
170
+    /**
171
+     * Set the path currently being compiled.
172
+     *
173
+     * @param  string  $path
174
+     * @return void
175
+     */
176
+    public function setPath($path)
177
+    {
178
+        $this->path = $path;
179
+    }
180
+
181
+    /**
182
+     * Compile the given Blade template contents.
183
+     *
184
+     * @param  string  $value
185
+     * @return string
186
+     */
187
+    public function compileString($value)
188
+    {
189
+        if (strpos($value, '@verbatim') !== false) {
190
+            $value = $this->storeVerbatimBlocks($value);
191
+        }
192
+
193
+        $this->footer = [];
194
+
195
+        if (strpos($value, '@php') !== false) {
196
+            $value = $this->storePhpBlocks($value);
197
+        }
198
+
199
+        $result = '';
200
+
201
+        // Here we will loop through all of the tokens returned by the Zend lexer and
202
+        // parse each one into the corresponding valid PHP. We will then have this
203
+        // template as the correctly rendered PHP that can be rendered natively.
204
+        foreach (token_get_all($value) as $token) {
205
+            $result .= is_array($token) ? $this->parseToken($token) : $token;
206
+        }
207
+
208
+        if (! empty($this->rawBlocks)) {
209
+            $result = $this->restoreRawContent($result);
210
+        }
211
+
212
+        // If there are any footer lines that need to get added to a template we will
213
+        // add them here at the end of the template. This gets used mainly for the
214
+        // template inheritance via the extends keyword that should be appended.
215
+        if (count($this->footer) > 0) {
216
+            $result = $this->addFooters($result);
217
+        }
218
+
219
+        return $result;
220
+    }
221
+
222
+    /**
223
+     * Store the verbatim blocks and replace them with a temporary placeholder.
224
+     *
225
+     * @param  string  $value
226
+     * @return string
227
+     */
228
+    protected function storeVerbatimBlocks($value)
229
+    {
230
+        return preg_replace_callback('/(?<!@)@verbatim(.*?)@endverbatim/s', function ($matches) {
231
+            return $this->storeRawBlock($matches[1]);
232
+        }, $value);
233
+    }
234
+
235
+    /**
236
+     * Store the PHP blocks and replace them with a temporary placeholder.
237
+     *
238
+     * @param  string  $value
239
+     * @return string
240
+     */
241
+    protected function storePhpBlocks($value)
242
+    {
243
+        return preg_replace_callback('/(?<!@)@php(.*?)@endphp/s', function ($matches) {
244
+            return $this->storeRawBlock("<?php{$matches[1]}?>");
245
+        }, $value);
246
+    }
247
+
248
+    /**
249
+     * Store a raw block and return a unique raw placeholder.
250
+     *
251
+     * @param  string  $value
252
+     * @return string
253
+     */
254
+    protected function storeRawBlock($value)
255
+    {
256
+        return $this->getRawPlaceholder(
257
+            array_push($this->rawBlocks, $value) - 1
258
+        );
259
+    }
260
+
261
+    /**
262
+     * Replace the raw placeholders with the original code stored in the raw blocks.
263
+     *
264
+     * @param  string  $result
265
+     * @return string
266
+     */
267
+    protected function restoreRawContent($result)
268
+    {
269
+        $result = preg_replace_callback('/'.$this->getRawPlaceholder('(\d+)').'/', function ($matches) {
270
+            return $this->rawBlocks[$matches[1]];
271
+        }, $result);
272
+
273
+        $this->rawBlocks = [];
274
+
275
+        return $result;
276
+    }
277
+
278
+    /**
279
+     * Get a placeholder to temporary mark the position of raw blocks.
280
+     *
281
+     * @param  int|string  $replace
282
+     * @return string
283
+     */
284
+    protected function getRawPlaceholder($replace)
285
+    {
286
+        return str_replace('#', $replace, '@__raw_block_#__@');
287
+    }
288
+
289
+    /**
290
+     * Add the stored footers onto the given content.
291
+     *
292
+     * @param  string  $result
293
+     * @return string
294
+     */
295
+    protected function addFooters($result)
296
+    {
297
+        return ltrim($result, PHP_EOL)
298
+                .PHP_EOL.implode(PHP_EOL, array_reverse($this->footer));
299
+    }
300
+
301
+    /**
302
+     * Parse the tokens from the template.
303
+     *
304
+     * @param  array  $token
305
+     * @return string
306
+     */
307
+    protected function parseToken($token)
308
+    {
309
+        [$id, $content] = $token;
310
+
311
+        if ($id == T_INLINE_HTML) {
312
+            foreach ($this->compilers as $type) {
313
+                $content = $this->{"compile{$type}"}($content);
314
+            }
315
+        }
316
+
317
+        return $content;
318
+    }
319
+
320
+    /**
321
+     * Execute the user defined extensions.
322
+     *
323
+     * @param  string  $value
324
+     * @return string
325
+     */
326
+    protected function compileExtensions($value)
327
+    {
328
+        foreach ($this->extensions as $compiler) {
329
+            $value = call_user_func($compiler, $value, $this);
330
+        }
331
+
332
+        return $value;
333
+    }
334
+
335
+    /**
336
+     * Compile Blade statements that start with "@".
337
+     *
338
+     * @param  string  $value
339
+     * @return string
340
+     */
341
+    protected function compileStatements($value)
342
+    {
343
+        return preg_replace_callback(
344
+            '/\B@(@?\w+(?:::\w+)?)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x', function ($match) {
345
+                return $this->compileStatement($match);
346
+            }, $value
347
+        );
348
+    }
349
+
350
+    /**
351
+     * Compile a single Blade @ statement.
352
+     *
353
+     * @param  array  $match
354
+     * @return string
355
+     */
356
+    protected function compileStatement($match)
357
+    {
358
+        if (Str::contains($match[1], '@')) {
359
+            $match[0] = isset($match[3]) ? $match[1].$match[3] : $match[1];
360
+        } elseif (isset($this->customDirectives[$match[1]])) {
361
+            $match[0] = $this->callCustomDirective($match[1], Arr::get($match, 3));
362
+        } elseif (method_exists($this, $method = 'compile'.ucfirst($match[1]))) {
363
+            $match[0] = $this->$method(Arr::get($match, 3));
364
+        }
365
+
366
+        return isset($match[3]) ? $match[0] : $match[0].$match[2];
367
+    }
368
+
369
+    /**
370
+     * Call the given directive with the given value.
371
+     *
372
+     * @param  string  $name
373
+     * @param  string|null  $value
374
+     * @return string
375
+     */
376
+    protected function callCustomDirective($name, $value)
377
+    {
378
+        if (Str::startsWith($value, '(') && Str::endsWith($value, ')')) {
379
+            $value = Str::substr($value, 1, -1);
380
+        }
381
+
382
+        return call_user_func($this->customDirectives[$name], trim($value));
383
+    }
384
+
385
+    /**
386
+     * Strip the parentheses from the given expression.
387
+     *
388
+     * @param  string  $expression
389
+     * @return string
390
+     */
391
+    public function stripParentheses($expression)
392
+    {
393
+        if (Str::startsWith($expression, '(')) {
394
+            $expression = substr($expression, 1, -1);
395
+        }
396
+
397
+        return $expression;
398
+    }
399
+
400
+    /**
401
+     * Register a custom Blade compiler.
402
+     *
403
+     * @param  callable  $compiler
404
+     * @return void
405
+     */
406
+    public function extend(callable $compiler)
407
+    {
408
+        $this->extensions[] = $compiler;
409
+    }
410
+
411
+    /**
412
+     * Get the extensions used by the compiler.
413
+     *
414
+     * @return array
415
+     */
416
+    public function getExtensions()
417
+    {
418
+        return $this->extensions;
419
+    }
420
+
421
+    /**
422
+     * Register an "if" statement directive.
423
+     *
424
+     * @param  string  $name
425
+     * @param  callable  $callback
426
+     * @return void
427
+     */
428
+    public function if($name, callable $callback)
429
+    {
430
+        $this->conditions[$name] = $callback;
431
+
432
+        $this->directive($name, function ($expression) use ($name) {
433
+            return $expression !== ''
434
+                    ? "<?php if (\Illuminate\Support\Facades\Blade::check('{$name}', {$expression})): ?>"
435
+                    : "<?php if (\Illuminate\Support\Facades\Blade::check('{$name}')): ?>";
436
+        });
437
+
438
+        $this->directive('else'.$name, function ($expression) use ($name) {
439
+            return $expression !== ''
440
+                ? "<?php elseif (\Illuminate\Support\Facades\Blade::check('{$name}', {$expression})): ?>"
441
+                : "<?php elseif (\Illuminate\Support\Facades\Blade::check('{$name}')): ?>";
442
+        });
443
+
444
+        $this->directive('end'.$name, function () {
445
+            return '<?php endif; ?>';
446
+        });
447
+    }
448
+
449
+    /**
450
+     * Check the result of a condition.
451
+     *
452
+     * @param  string  $name
453
+     * @param  array  $parameters
454
+     * @return bool
455
+     */
456
+    public function check($name, ...$parameters)
457
+    {
458
+        return call_user_func($this->conditions[$name], ...$parameters);
459
+    }
460
+
461
+    /**
462
+     * Register a component alias directive.
463
+     *
464
+     * @param  string  $path
465
+     * @param  string|null  $alias
466
+     * @return void
467
+     */
468
+    public function component($path, $alias = null)
469
+    {
470
+        $alias = $alias ?: Arr::last(explode('.', $path));
471
+
472
+        $this->directive($alias, function ($expression) use ($path) {
473
+            return $expression
474
+                        ? "<?php \$__env->startComponent('{$path}', {$expression}); ?>"
475
+                        : "<?php \$__env->startComponent('{$path}'); ?>";
476
+        });
477
+
478
+        $this->directive('end'.$alias, function ($expression) {
479
+            return '<?php echo $__env->renderComponent(); ?>';
480
+        });
481
+    }
482
+
483
+    /**
484
+     * Register an include alias directive.
485
+     *
486
+     * @param  string  $path
487
+     * @param  string|null  $alias
488
+     * @return void
489
+     */
490
+    public function include($path, $alias = null)
491
+    {
492
+        $alias = $alias ?: Arr::last(explode('.', $path));
493
+
494
+        $this->directive($alias, function ($expression) use ($path) {
495
+            $expression = $this->stripParentheses($expression) ?: '[]';
496
+
497
+            return "<?php echo \$__env->make('{$path}', {$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>";
498
+        });
499
+    }
500
+
501
+    /**
502
+     * Register a handler for custom directives.
503
+     *
504
+     * @param  string  $name
505
+     * @param  callable  $handler
506
+     * @return void
507
+     */
508
+    public function directive($name, callable $handler)
509
+    {
510
+        if (! preg_match('/^\w+(?:::\w+)?$/x', $name)) {
511
+            throw new InvalidArgumentException("The directive name [{$name}] is not valid. Directive names must only contain alphanumeric characters and underscores.");
512
+        }
513
+
514
+        $this->customDirectives[$name] = $handler;
515
+    }
516
+
517
+    /**
518
+     * Get the list of custom directives.
519
+     *
520
+     * @return array
521
+     */
522
+    public function getCustomDirectives()
523
+    {
524
+        return $this->customDirectives;
525
+    }
526
+
527
+    /**
528
+     * Set the echo format to be used by the compiler.
529
+     *
530
+     * @param  string  $format
531
+     * @return void
532
+     */
533
+    public function setEchoFormat($format)
534
+    {
535
+        $this->echoFormat = $format;
536
+    }
537
+
538
+    /**
539
+     * Set the "echo" format to double encode entities.
540
+     *
541
+     * @return void
542
+     */
543
+    public function withDoubleEncoding()
544
+    {
545
+        $this->setEchoFormat('e(%s, true)');
546
+    }
547
+
548
+    /**
549
+     * Set the "echo" format to not double encode entities.
550
+     *
551
+     * @return void
552
+     */
553
+    public function withoutDoubleEncoding()
554
+    {
555
+        $this->setEchoFormat('e(%s, false)');
556
+    }
557
+}