├── .github ├── FUNDING.yml └── workflows │ ├── coverage.yml │ └── tests.yml ├── composer.json ├── config └── config.php └── src ├── Exception.php ├── ExceptionHandlerTrait.php ├── Install.php ├── PugBladeCompiler.php ├── PugCompiler.php ├── PugException.php ├── PugHandlerInterface.php ├── PugHandlerTrait.php ├── ServiceProvider.php └── config └── config.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: kylekatarnls, weotch 2 | open_collective: pug-php 3 | tidelift: packagist/pug-php/pug 4 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Coverage 2 | 3 | on: 4 | push: 5 | branches: [ '**' ] 6 | pull_request: 7 | branches: [ '**' ] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | php: ['8.2'] 17 | setup: ['stable'] 18 | 19 | name: PHP 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | 24 | - name: Setup PHP 25 | uses: shivammathur/setup-php@v2 26 | with: 27 | php-version: ${{ matrix.php }} 28 | tools: composer:v2 29 | coverage: pcov 30 | 31 | - name: Cache Composer packages 32 | id: composer-cache 33 | uses: actions/cache@v2 34 | with: 35 | path: vendor 36 | key: ${{ runner.os }}-${{ matrix.setup }}-php-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} 37 | restore-keys: | 38 | ${{ runner.os }}-${{ matrix.setup }}-php-${{ matrix.php }}- 39 | 40 | - name: Code Climate Test Reporter Preparation 41 | run: | 42 | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter 43 | chmod +x ./cc-test-reporter 44 | ./cc-test-reporter before-build 45 | env: 46 | CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} 47 | 48 | - name: Install dependencies 49 | if: steps.composer-cache.outputs.cache-hit != 'true' 50 | run: | 51 | ${{ matrix.php >= 8 && 'composer require --no-update phpunit/phpunit:^9.5.10 --no-interaction;' || '' }} 52 | composer update --prefer-dist --no-interaction ${{ format('--prefer-{0}', matrix.setup) || '' }} 53 | 54 | - name: Run test suite 55 | run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml 56 | 57 | - name: Code Climate Test Reporter 58 | if: ${{ env.CC_TEST_REPORTER_ID != '' }} 59 | run: | 60 | cp coverage.xml clover.xml 61 | bash <(curl -s https://codecov.io/bash) 62 | ./cc-test-reporter after-build --coverage-input-type clover --exit-code 0 63 | env: 64 | CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} 65 | CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} 66 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: [ '**' ] 6 | pull_request: 7 | branches: [ '**' ] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] 17 | setup: ['lowest', 'stable', 'next'] 18 | 19 | name: PHP ${{ matrix.php }} - ${{ matrix.setup }} 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | 24 | - name: Setup PHP 25 | uses: shivammathur/setup-php@v2 26 | with: 27 | php-version: ${{ matrix.php }} 28 | tools: composer:v2 29 | 30 | - name: Cache Composer packages 31 | id: composer-cache 32 | uses: actions/cache@v2 33 | with: 34 | path: vendor 35 | key: ${{ runner.os }}-${{ matrix.setup }}-php-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} 36 | restore-keys: | 37 | ${{ runner.os }}-${{ matrix.setup }}-php-${{ matrix.php }}- 38 | 39 | - name: Install dependencies 40 | if: steps.composer-cache.outputs.cache-hit != 'true' 41 | run: | 42 | ${{ matrix.php >= 8 && 'composer require --no-update phpunit/phpunit:^9.5.10 --no-interaction;' || '' }} 43 | composer update --prefer-dist --no-interaction ${{ matrix.setup != 'next' && format('--prefer-{0}', matrix.setup) || '' }} 44 | env: 45 | MULTI_TESTER_LABELS: install 46 | 47 | - name: Run test suite 48 | run: vendor/bin/phpunit --no-coverage --verbose 49 | env: 50 | MULTI_TESTER_LABELS: script 51 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bkwld/laravel-pug", 3 | "description": "Pug view adapter for Laravel", 4 | "type": "library", 5 | "require": { 6 | "php": "^7.2 || ^8.0", 7 | "illuminate/support": ">=6", 8 | "illuminate/view": ">=6", 9 | "phug/component": "^1.1.3", 10 | "pug-php/pug": "^3.3.1", 11 | "pug-php/pug-assets": "^1.0.1", 12 | "pug/installer": "^1.0.0", 13 | "composer-plugin-api": "^1.0 || ^2.0" 14 | }, 15 | "require-dev": { 16 | "composer/composer": "^1.2 || ^2.0", 17 | "phpunit/phpunit": "^8.5" 18 | }, 19 | "minimum-stability": "dev", 20 | "license": "MIT", 21 | "authors": [ 22 | { 23 | "name": "kylekatarnls", 24 | "homepage": "https://github.com/kylekatarnls" 25 | }, 26 | { 27 | "name": "Robert Reinhard", 28 | "email": "info@bukwild.com" 29 | } 30 | ], 31 | "autoload": { 32 | "psr-4": { 33 | "Bkwld\\LaravelPug\\": "src/" 34 | } 35 | }, 36 | "scripts": { 37 | "post-install-cmd": [ 38 | "Pug\\Installer\\Installer::onAutoloadDump" 39 | ], 40 | "post-update-cmd": [ 41 | "Pug\\Installer\\Installer::onAutoloadDump" 42 | ] 43 | }, 44 | "extra": { 45 | "branch-alias": { 46 | "dev-master": "2.x-dev" 47 | }, 48 | "installer": "Bkwld\\LaravelPug\\Install::publishVendor", 49 | "laravel": { 50 | "providers": [ 51 | "Bkwld\\LaravelPug\\ServiceProvider" 52 | ] 53 | } 54 | }, 55 | "config": { 56 | "allow-plugins": { 57 | "nodejs-php-fallback/nodejs-php-fallback": true, 58 | "pug/installer": true 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /config/config.php: -------------------------------------------------------------------------------- 1 | = 5. 5 | * Passthrough php-pug config options. 6 | * 7 | * @see https://www.phug-lang.com/#options 8 | */ 9 | 10 | ]; 11 | -------------------------------------------------------------------------------- /src/Exception.php: -------------------------------------------------------------------------------- 1 | container->has('laravel-pug.pug')) { 15 | /** @var Pug $pug */ 16 | $pug = $this->container->get('laravel-pug.pug'); 17 | 18 | try { 19 | $compiler = $pug->getCompiler(); 20 | $exception = $compiler->getFormatter()->getDebugError( 21 | $exception, 22 | file_get_contents($exception->getFile()), 23 | $compiler->getPath() 24 | ); 25 | } catch (\Throwable $caughtException) { 26 | $exception = $caughtException; 27 | } catch (\Exception $caughtException) { 28 | $exception = $caughtException; 29 | } 30 | } 31 | 32 | if (!$request->expectsJson() && $exception instanceof LocatedException) { 33 | $className = get_class($exception->getPrevious() ?: $exception); 34 | $location = $exception->getLocation(); 35 | $line = $location->getLine(); 36 | $offset = $location->getOffset(); 37 | $path = realpath($location->getPath()); 38 | $content = $response->getContent(); 39 | $content = str_replace('Phug\\Util\\Exception\\LocatedException', $className, $content); 40 | $posNamespace = max(0, strrpos($className, '\\')); 41 | 42 | $content = preg_replace('/ 43 | 44 | ([^<]+)LocatedException<\/span>\s* 45 | <\/div> 46 | /x', '
'. 47 | mb_substr($className, 0, $posNamespace). 48 | ''.mb_substr($className, $posNamespace).'
', $content, 1); 49 | $content = preg_replace_callback('/ 50 | (.+?)<\/span> 51 | /x', function ($match) use ($className) { 52 | $input = trim(strip_tags($match[1])); 53 | 54 | if ($input !== 'Phug\\Util\\Exception\\LocatedException') { 55 | return $match[0]; 56 | } 57 | 58 | return '
'. 59 | implode('
\\
', explode('\\', $className)). 60 | '
'; 61 | }, $content, 1); 62 | $content = preg_replace_callback('/ 63 | (\s* 64 | )([^<]+)(<\/div>)(\d+)(<\/span>)(\s* 66 | <\/div>) 67 | /x', function ($match) use ($line, $offset, $path) { 68 | $base = realpath(base_path()); 69 | 70 | if (strpos($path, $base) === 0) { 71 | $path = '…'.mb_substr($path, mb_strlen($base)); 72 | } 73 | 74 | return $match[1].$path.$match[3]. 75 | $line.$match[5].' offset '.$offset.' '. 76 | $match[6]; 77 | }, $content, 1); 78 | $content = preg_replace_callback('/ 79 | () 80 | ([^<]+) 81 | (<\/pre>) 82 | /x', function ($match) use ($path, $line) { 83 | $code = []; 84 | $source = explode("\n", @file_get_contents($path)); 85 | $before = 19; 86 | $after = 7; 87 | $start = max(0, $line - $before); 88 | 89 | for ($i = $start; $i < $line + $after; $i++) { 90 | if (isset($source[$i])) { 91 | $code[] = $source[$i]; 92 | } 93 | } 94 | 95 | $code = implode("\n", $code); 96 | 97 | return $match[1].($start + 1).$match[3].$code.$match[5]; 98 | }, $content); 99 | 100 | if ($offset) { 101 | $content = str_replace('', '', $content); 121 | } 122 | 123 | $response->setContent($content); 124 | } 125 | 126 | return $response; 127 | } 128 | } 129 | 130 | // @codeCoverageIgnoreEnd 131 | -------------------------------------------------------------------------------- /src/Install.php: -------------------------------------------------------------------------------- 1 | getIO(); 20 | 21 | $cmd = 'php artisan vendor:publish --provider="'.ServiceProvider::class.'"'; 22 | 23 | $io->write("> $cmd\n".@shell_exec($cmd)); 24 | } 25 | 26 | chdir($currentDirectory); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/PugBladeCompiler.php: -------------------------------------------------------------------------------- 1 | construct($pugTarget, $files, $config, $defaultCachePath, $compiler); 29 | } 30 | 31 | /** 32 | * Copy custom blade directives. 33 | */ 34 | protected function enableBladeDirectives(): void 35 | { 36 | /** @var \Illuminate\View\Compilers\BladeCompiler $blade */ 37 | $blade = Blade::getFacadeRoot(); 38 | 39 | if ($blade && method_exists($blade, 'getCustomDirectives')) { 40 | foreach ($blade->getCustomDirectives() as $name => $directive) { 41 | $this->directive($name, $directive); 42 | } 43 | } 44 | } 45 | 46 | /** 47 | * Compile the view at the given path. 48 | * 49 | * @param string $path 50 | * 51 | * @throws \InvalidArgumentException 52 | * 53 | * @return void 54 | */ 55 | public function compile($path = null): void 56 | { 57 | $app = Blade::getFacadeApplication(); 58 | 59 | if (isset($app['view'])) { 60 | $this->enableBladeDirectives(); 61 | } 62 | 63 | $this->footer = []; 64 | $compiler = $this->compiler instanceof BladeCompiler ? $this->compiler : $this; 65 | $this->compileWith($path, [$compiler, 'compileString']); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/PugCompiler.php: -------------------------------------------------------------------------------- 1 | construct($pugTarget, $files, $config, $defaultCachePath, $compiler); 23 | } 24 | 25 | /** 26 | * Compile the view at the given path. 27 | * 28 | * @param string $path 29 | * 30 | * @throws \InvalidArgumentException 31 | * 32 | * @return void 33 | */ 34 | public function compile($path): void 35 | { 36 | $this->compileWith($path); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/PugException.php: -------------------------------------------------------------------------------- 1 | getMessage(); 24 | $code = $previous->getCode(); 25 | $compiler = $context->getCompiler(); 26 | $file = $previous->getFile(); 27 | $line = $previous->getLine(); 28 | 29 | if ($compiler instanceof PugHandlerInterface) { 30 | $print = 'error-'.md5_file($file).'-'.$line.'-'.md5($previous->getTraceAsString()); 31 | $cachePath = storage_path('framework/views/'.$print.'.txt'); 32 | $location = $this->getLocation($compiler, $cachePath, $file, $previous); 33 | 34 | if ($location) { 35 | $file = $location->getPath(); 36 | $line = $location->getLine(); 37 | } 38 | } 39 | 40 | parent::__construct($message, $code, 1, $file, $line, $previous); 41 | } 42 | 43 | protected function getLocation(PugHandlerInterface $compiler, string $cachePath, string $file, Throwable $previous): ?SourceLocationInterface 44 | { 45 | if (file_exists($cachePath)) { 46 | return unserialize(file_get_contents($cachePath)); 47 | } 48 | 49 | $location = null; 50 | $pug = $compiler->getPug(); 51 | $error = $pug->getDebugFormatter()->getDebugError( 52 | $previous, 53 | file_get_contents($file), 54 | $file 55 | ); 56 | 57 | if ($error instanceof LocatedException && ($location = $error->getLocation())) { 58 | file_put_contents($cachePath, serialize($location)); 59 | } 60 | 61 | return $location; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/PugHandlerInterface.php: -------------------------------------------------------------------------------- 1 | pugTarget = $pugTarget; 40 | $this->compiler = $compiler; 41 | $cachePath = null; 42 | 43 | foreach (['cache_dir', 'cache', 'defaultCache'] as $name) { 44 | if (isset($config[$name])) { 45 | $cachePath = $config[$name]; 46 | 47 | break; 48 | } 49 | } 50 | 51 | if (!$cachePath) { 52 | $cachePath = $defaultCachePath ?: $this->getCachePath(); 53 | } 54 | 55 | parent::__construct($files, $cachePath); 56 | } 57 | 58 | /** 59 | * Lazy load Pug and return the instance. 60 | * 61 | * @return Pug 62 | */ 63 | public function getPug() 64 | { 65 | if (!$this->pug) { 66 | $this->pug = $this->pugTarget[0][$this->pugTarget[1]]; 67 | } 68 | 69 | return $this->pug; 70 | } 71 | 72 | /** 73 | * Returns cache path. 74 | * 75 | * @return string $cachePath 76 | */ 77 | public function getCachePath() 78 | { 79 | if ($this->cachePath) { 80 | return $this->cachePath; 81 | } 82 | 83 | $cachePath = $this->getOption('cache'); 84 | 85 | return is_string($cachePath) ? $cachePath : $this->getOption('defaultCache'); 86 | } 87 | 88 | /** 89 | * Get an option from pug engine or default value. 90 | * 91 | * @param string $name 92 | * @param null $default 93 | * 94 | * @return mixed|null 95 | */ 96 | public function getOption($name, $default = null) 97 | { 98 | $pug = $this->getPug(); 99 | 100 | try { 101 | if (method_exists($pug, 'hasOption') && !$pug->hasOption($name)) { 102 | throw new InvalidArgumentException('invalid option'); 103 | } 104 | 105 | return $pug->getOption($name); 106 | } catch (InvalidArgumentException $exception) { 107 | return $default; 108 | } 109 | } 110 | 111 | /** 112 | * @param string $cachePath 113 | */ 114 | public function setCachePath($cachePath) 115 | { 116 | $this->cachePath = $cachePath; 117 | $this->getPug()->setOption('cache', $cachePath); 118 | } 119 | 120 | /** 121 | * Returns true if the path has an expired imports linked. 122 | */ 123 | private function hasExpiredImport($path): bool 124 | { 125 | $compiled = $this->getCompiledPath($path); 126 | $importsMap = $compiled.'.imports.serialize.txt'; 127 | $files = $this->files; 128 | 129 | if (!$files->exists($importsMap)) { 130 | return true; 131 | } 132 | 133 | $importPaths = unserialize($files->get($importsMap)); 134 | $time = $files->lastModified($compiled); 135 | 136 | foreach ($importPaths as $importPath) { 137 | if (!$files->exists($importPath) || $files->lastModified($importPath) >= $time) { 138 | return true; 139 | } 140 | } 141 | 142 | return false; 143 | } 144 | 145 | /** 146 | * Determine if the view at the given path is expired. 147 | * 148 | * @param string $path 149 | * 150 | * @return bool 151 | */ 152 | public function isExpired($path): bool 153 | { 154 | if (!$this->cachePath || parent::isExpired($path)) { 155 | return true; 156 | } 157 | 158 | return is_subclass_of('\Pug\Pug', '\Phug\Renderer') && $this->hasExpiredImport($path); 159 | } 160 | 161 | /** 162 | * Return path and set it or get it from the instance. 163 | * 164 | * @param string $path 165 | * 166 | * @throws InvalidArgumentException 167 | * 168 | * @return string 169 | */ 170 | public function extractPath($path): ?string 171 | { 172 | if ($path && method_exists($this, 'setPath')) { 173 | $this->setPath($path); 174 | } 175 | 176 | if (!$path && method_exists($this, 'getPath')) { 177 | $path = $this->getPath(); 178 | } 179 | 180 | if (!$path) { 181 | throw new InvalidArgumentException('Missing path argument.'); 182 | } 183 | 184 | return $path; 185 | } 186 | 187 | /** 188 | * Returns the object the more appropriate to compile. 189 | */ 190 | public function getCompiler(): CompilerInterface 191 | { 192 | return $this->getPug()->getCompiler(); 193 | } 194 | 195 | /** 196 | * Compile the view at the given path. 197 | * 198 | * @param string $path 199 | * @param callable|null $callback 200 | * 201 | * @throws InvalidArgumentException 202 | * 203 | * @return void 204 | */ 205 | public function compileWith($path, callable $callback = null): void 206 | { 207 | $path = $this->extractPath($path); 208 | 209 | if ($this->cachePath) { 210 | $pug = $this->getCompiler(); 211 | $compiled = $this->getCompiledPath($path); 212 | $engine = $this->getPug(); 213 | $importCarrier = null; 214 | 215 | $contents = $engine->compile($this->files->get($path), $path); 216 | 217 | if ($callback) { 218 | $contents = call_user_func($callback, $contents); 219 | } 220 | 221 | if ($pug instanceof Compiler) { 222 | if ($importCarrier === null) { 223 | $importCarrier = $engine->getCompiler(); 224 | } 225 | 226 | $this->files->put( 227 | $compiled.'.imports.serialize.txt', 228 | serialize($importCarrier->getCurrentImportPaths()) 229 | ); 230 | 231 | if ($pug->getOption('debug') && class_exists('Facade\\Ignition\\Exceptions\\ViewException')) { 232 | $contents = "$contentsfiles->put($compiled, $contents); 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | hasOption($name)) { 28 | $pug->setOption($name, call_user_func($value)); 29 | } 30 | } 31 | 32 | protected function getDefaultCache(): string 33 | { 34 | return storage_path('/framework/views'); 35 | } 36 | 37 | protected function getAssetsDirectories(): array 38 | { 39 | return array_map(function ($params) { 40 | [$function, $arg] = $params; 41 | 42 | return function_exists($function) ? call_user_func($function, $arg) : null; 43 | }, [ 44 | ['resource_path', 'assets'], 45 | ['app_path', 'views/assets'], 46 | ['app_path', 'assets'], 47 | ['app_path', 'views'], 48 | ['app_path', ''], 49 | ['base_path', ''], 50 | ]); 51 | } 52 | 53 | public function getPugEngine(): Pug 54 | { 55 | $config = $this->getConfig(); 56 | 57 | if (!isset($config['extensions']) && $this->app['view']) { 58 | $extensions = array_keys(array_filter($this->app['view']->getExtensions(), function ($engine) { 59 | $engines = explode('.', $engine); 60 | 61 | return in_array('pug', $engines); 62 | })); 63 | 64 | $config['extensions'] = array_map(function ($extension) { 65 | return ".$extension"; 66 | }, $extensions); 67 | } 68 | 69 | $pug = new Pug($config); 70 | 71 | if ($config['assets'] ?? true) { 72 | $this->assets = new Assets($pug); 73 | $getEnv = ['App', 'environment']; 74 | $this->assets->setEnvironment(is_callable($getEnv) ? call_user_func($getEnv) : 'production'); 75 | } 76 | 77 | if ($config['component'] ?? true) { 78 | ComponentExtension::enable($pug); 79 | 80 | $this->componentExtension = $pug->getModule(ComponentExtension::class); 81 | } 82 | 83 | // Determine the cache dir if not configured 84 | $this->setDefaultOption($pug, 'defaultCache', [$this, 'getDefaultCache']); 85 | 86 | // Determine assets input directory 87 | $this->setDefaultOption($pug, 'assetDirectory', [$this, 'getAssetsDirectories']); 88 | 89 | // Determine assets output directory 90 | $this->setDefaultOption($pug, 'outputDirectory', [$this, 'getOutputDirectory']); 91 | 92 | // Optimize paths 93 | $this->setDefaultOption($pug, 'paths', array_unique($pug->getOption('paths'))); 94 | 95 | $pug->getCompiler()->setOption('mixin_keyword', $pug->getOption('mixin_keyword')); 96 | 97 | return $pug; 98 | } 99 | 100 | protected function getPugAssets(): ?Assets 101 | { 102 | return $this->app['laravel-pug.pug'] ? $this->assets : null; 103 | } 104 | 105 | protected function getOutputDirectory(): ?string 106 | { 107 | return function_exists('public_path') ? public_path() : null; 108 | } 109 | 110 | protected function getCompilerCreator($compilerClass): Closure 111 | { 112 | return function ($app) use ($compilerClass) { 113 | return new $compilerClass( 114 | [$app, 'laravel-pug.pug'], 115 | $app['files'], 116 | $this->getConfig(), 117 | $this->getDefaultCache(), 118 | $this->app['blade.compiler'] ?? null 119 | ); 120 | }; 121 | } 122 | 123 | /** 124 | * Register the service provider. 125 | */ 126 | public function register(): void 127 | { 128 | $this->mergeConfigFrom(__DIR__.'/../config/config.php', 'laravel-pug'); 129 | 130 | // Bind the pug assets module 131 | $this->app->singleton('laravel-pug.pug-assets', function () { 132 | return $this->getPugAssets(); 133 | }); 134 | 135 | // Bind the package-configured Pug instance 136 | $this->app->singleton('laravel-pug.pug', function () { 137 | return $this->getPugEngine(); 138 | }); 139 | 140 | // Bind the Pug compiler 141 | $this->app->singleton( 142 | PugCompiler::class, 143 | $this->getCompilerCreator(PugCompiler::class) 144 | ); 145 | 146 | // Bind the Pug Blade compiler 147 | $this->app->singleton( 148 | PugBladeCompiler::class, 149 | $this->getCompilerCreator(PugBladeCompiler::class) 150 | ); 151 | } 152 | 153 | /** 154 | * Bootstrap the application events. 155 | * 156 | * @throws Exception for unsupported Laravel version 157 | */ 158 | public function boot(): void 159 | { 160 | if (function_exists('config_path')) { 161 | $this->publishes([ 162 | __DIR__.'/../config/config.php' => config_path('laravel-pug.php'), 163 | ], 'laravel-pug'); 164 | } 165 | 166 | // Register compilers 167 | $this->registerPugCompiler(); 168 | $this->registerPugBladeCompiler(); 169 | } 170 | 171 | /** 172 | * Returns the view engine resolver according to current framework (laravel/lumen). 173 | */ 174 | public function getEngineResolver(): EngineResolver 175 | { 176 | return isset($this->app['view.engine.resolver']) 177 | ? $this->app['view.engine.resolver'] 178 | : $this->app['view']->getEngineResolver(); 179 | } 180 | 181 | /** 182 | * Register the regular Pug compiler. 183 | */ 184 | public function registerPugCompiler(string $subExtension = ''): void 185 | { 186 | $mainExtension = 'pug'.$subExtension; 187 | 188 | // Add resolver 189 | $this->getEngineResolver()->register($mainExtension, function () use ($subExtension) { 190 | return new CompilerEngine( 191 | $this->app['Bkwld\LaravelPug\Pug'.ucfirst(ltrim($subExtension, '.')).'Compiler'] 192 | ); 193 | }); 194 | 195 | $this->app['view']->addExtension($mainExtension, $mainExtension); 196 | 197 | if ($subExtension !== '') { 198 | $this->app['view']->addExtension(substr($subExtension, 1).'.pug', $mainExtension); 199 | } 200 | } 201 | 202 | /** 203 | * Register the blade compiler compiler. 204 | */ 205 | public function registerPugBladeCompiler(): void 206 | { 207 | $this->registerPugCompiler('.blade'); 208 | } 209 | 210 | /** 211 | * Get the configuration from the current app config file. 212 | */ 213 | public function getConfig(): array 214 | { 215 | $config = $this->app->make('config'); 216 | 217 | return array_merge([ 218 | 'allow_composite_extensions' => true, 219 | ], [ 220 | 'paths' => $config->get('view.paths'), 221 | 'debug' => $config->get('app.debug'), 222 | ], $this->app->make('config')->get('laravel-pug')); 223 | } 224 | 225 | /** 226 | * Get the services provided by the provider. 227 | */ 228 | public function provides(): array 229 | { 230 | return [ 231 | PugCompiler::class, 232 | PugBladeCompiler::class, 233 | 'laravel-pug.pug', 234 | ]; 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 |