8000 Improve how the `ide-twig.json` file is generated by m-vo · Pull Request #8200 · contao/contao · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Improve how the ide-twig.json file is generated #8200

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: 5.x
Choose a base branch
from
7 changes: 7 additions & 0 deletions core-bundle/config/commands.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ services:
- '%kernel.project_dir%'
- '@contao.twig.inspector'

contao.command.dump_twig_ide_file:
class: Contao\CoreBundle\Command\DumpTwigIDEFileCommand
arguments:
- '@contao.twig.ide.namespace_lookup_file_generator'
- '%kernel.build_dir%'
- '%kernel.project_dir%'

contao.command.filesync:
class: Contao\CoreBundle\Command\FilesyncCommand
arguments:
Expand Down
13 changes: 11 additions & 2 deletions core-bundle/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1298,8 +1298,6 @@ services:
class: Contao\CoreBundle\Twig\Loader\ContaoFilesystemLoaderWarmer
arguments:
- '@contao.twig.filesystem_loader'
- '%kernel.cache_dir%'
- '%kernel.environment%'

contao.twig.finder_factory:
class: Contao\CoreBundle\Twig\Finder\FinderFactory
Expand Down Expand Up @@ -1329,6 +1327,17 @@ services:
contao.twig.highlighter_runtime:
class: Contao\CoreBundle\Twig\Runtime\HighlighterRuntime

contao.twig.ide.namespace_lookup_file_generator:
class: Contao\CoreBundle\Twig\IDE\NamespaceLookupFileGenerator
arguments:
- '@contao.twig.filesystem_loader'

contao.twig.ide.namespace_lookup_file_warmer:
class: Contao\CoreBundle\Twig\IDE\NamespaceLookupFileWarmer
arguments:
- '@contao.twig.ide.namespace_lookup_file_generator'
- '%kernel.environment%'

contao.twig.insert_tag_runtime:
class: Contao\CoreBundle\Twig\Runtime\InsertTagRuntime
arguments:
Expand Down
2 changes: 1 addition & 1 deletion core-bundle/contao/library/Contao/Automator.php
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ public function generateInternalCache()
$container = System::getContainer();

$warmer = $container->get('contao.cache.warmer');
$warmer->warmUp($container->getParameter('kernel.cache_dir'));
$warmer->warmUp($container->getParameter('kernel.cache_dir'), $container->getParameter('kernel.build_dir'));

System::getContainer()->get('monolog.logger.contao.cron')->info('Generated the internal cache');
}
Expand Down
73 changes: 73 additions & 0 deletions core-bundle/src/Command/DumpTwigIDEFileCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

declare(strict_types=1);

/*
* This file is part of Contao.
*
* (c) Leo Feyer
*
* @license LGPL-3.0-or-later
*/

namespace Contao\CoreBundle\Command;

use Contao\CoreBundle\Twig\IDE\NamespaceLookupFileGenerator;
use Contao\CoreBundle\Twig\IDE\NamespaceLookupFileWarmer;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Path;

#[AsCommand(
name: 'contao:dump-twig-ide-file',
description: 'Dumps an "ide-twig.json" namespace lookup file that allows IDEs to understand the Contao template hierarchy.',
)]
class DumpTwigIDEFileCommand extends Command
{
public function __construct(
private readonly NamespaceLookupFileGenerator $namespaceLookupFileGenerator,
private readonly string $buildDir,
private readonly string $projectDir,
) {
parent::__construct();
}

protected function configure(): void
{
$defaultDir = Path::makeRelative(
Path::join($this->buildDir, NamespaceLookupFileWarmer::CONTAO_IDE_DIR),
$this->projectDir,
);

$this
->addArgument('dir', InputArgument::OPTIONAL, 'Target path relative to the project directory.', $defaultDir)
;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$targetDir = Path::canonicalize($input->getArgument('dir'));
$io = new SymfonyStyle($input, $output);

try {
$this->namespaceLookupFileGenerator->write(Path::makeAbsolute($targetDir, $this->projectDir));
} catch (IOException) {
$io->error(\sprintf('Unable to write the "%s" namespace lookup file to "%s".', $targetDir, NamespaceLookupFileGenerator::FILE_NAME));

return Command::FAILURE;
}

$io->success(\sprintf('The namespace lookup file was written to "%s/%s". Make sure the file is not ignored by your IDE.', $targetDir, NamespaceLookupFileGenerator::FILE_NAME));

if ($this->getDefinition()->getArgument('dir')->getDefault() !== $input->getArgument('dir')) {
$io->info('Re-run this command after installing extensions or introducing new @Contao namespace locations.');
}

return Command::SUCCESS;
}
}
56 changes: 56 additions & 0 deletions core-bundle/src/Twig/IDE/NamespaceLookupFileGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace Contao\CoreBundle\Twig\IDE;

use Contao\CoreBundle\Twig\ContaoTwigUtil;
use Contao\CoreBundle\Twig\Loader\ContaoFilesystemLoader;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Path;

class NamespaceLookupFileGenerator
{
public const FILE_NAME = 'ide-twig.json';

public function __construct(
private readonly ContaoFilesystemLoader $loader,
private Filesystem|null $filesystem = null,
) {
}

/**
* Writes an "ide-twig.json" file with path mapping information that enables IDE
* auto-completion for all our dynamic namespaces. The file will be dumped to the
* given $targetDir and all contained paths will be relative to this directory.
*/
public function write(string $targetDir): void
{
$mappings = [];

foreach ($this->loader->getInheritanceChains() as $chain) {
foreach ($chain as $path => $name) {
[$namespace, $file] = ContaoTwigUtil::parseContaoName($name);
$templateDir = preg_replace('%(.*)/'.preg_quote($file, '%').'%', '$1', $path);

$mappings[Path::makeRelative($templateDir, $targetDir)] = $namespace;
}
}

$data = [];

foreach ($mappings as $path => $namespace) {
$data['namespaces'][] = ['namespace' => 'Contao', 'path' => $path];
$data['namespaces'][] = ['namespace' => $namespace, 'path' => $path];
}

if (!$this->filesystem) {
$this->filesystem = new Filesystem();
}

$this->filesystem->dumpFile(
Path::join($targetDir, self::FILE_NAME),
json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES),
);
}
}
40 changes: 40 additions & 0 deletions core-bundle/src/Twig/IDE/NamespaceLookupFileWarmer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Contao\CoreBundle\Twig\IDE;

use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Path;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;

class NamespaceLookupFileWarmer implements CacheWarmerInterface
{
public const CONTAO_IDE_DIR = 'contao-ide';

public function __construct(
private readonly NamespaceLookupFileGenerator $namespaceLookupFileGenerator,
private readonly string $environment,
) {
}

public function isOptional(): bool
{
return false;
}

public function warmUp(string $cacheDir, string|null $buildDir = null): array
{
if ('dev' !== $this->environment || null === $buildDir) {
return [];
}

try {
$this->namespaceLookupFileGenerator->write(Path::join($buildDir, self::CONTAO_IDE_DIR));
} catch (IOException) {
// ignore
}

return [];
}
}
50 changes: 0 additions & 50 deletions core-bundle/src/Twig/Loader/ContaoFilesystemLoaderWarmer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@

namespace Contao\CoreBundle\Twig\Loader;

use Contao\CoreBundle\Twig\ContaoTwigUtil;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Path;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;

/**
Expand All @@ -25,64 +21,18 @@ class ContaoFilesystemLoaderWarmer implements CacheWarmerInterface
{
public function __construct(
private readonly ContaoFilesystemLoader $loader,
private readonly string $cacheDir,
private readonly string $environment,
private Filesystem|null $filesystem = null,
) {
}

public function warmUp(string|null $cacheDir = null, string|null $buildDir = null): array
{
$this->loader->warmUp();

if ('dev' === $this->environment) {
$this->writeIdeAutoCompletionMapping($cacheDir ?? $this->cacheDir);
}

return [];
}

public function isOptional(): bool
{
return true;
}

/**
* Writes an "ide-twig.json" file with path mapping information that enables IDE
* auto-completion for all our dynamic namespaces.
*/
private function writeIdeAutoCompletionMapping(string $cacheDir): void
{
$mappings = [];
$targetDir = Path::join($cacheDir, 'contao');

foreach ($this->loader->getInheritanceChains() as $chain) {
foreach ($chain as $path => $name) {
[$namespace, $file] = ContaoTwigUtil::parseContaoName($name);
$templateDir = preg_replace('%(.*)/'.preg_quote($file, '%').'%', '$1', $path);

$mappings[Path::makeRelative($templateDir, $targetDir)] = $namespace;
}
}

$data = [];

foreach ($mappings as $path => $namespace) {
$data['namespaces'][] = ['namespace' => 'Contao', 'path' => $path];
$data['namespaces'][] = ['namespace' => $namespace, 'path' => $path];
}

if (!$this->filesystem) {
$this->filesystem = new Filesystem();
}

try {
$this->filesystem->dumpFile(
Path::join($targetDir, 'ide-twig.json'),
json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES),
);
} catch (IOException) {
// ignore
}
}
}
60 changes: 60 additions & 0 deletions core-bundle/tests/Command/DumpTwigIDEFileCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

/*
* This file is part of Contao.
*
* (c) Leo Feyer
*
* @license LGPL-3.0-or-later
*/

namespace Contao\CoreBundle\Tests\Command;

use Contao\CoreBundle\Command\DumpTwigIDEFileCommand;
use Contao\CoreBundle\Tests\TestCase;
use Contao\CoreBundle\Twig\IDE\NamespaceLookupFileGenerator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;

class DumpTwigIDEFileCommandTest extends TestCase
{
public function testWritesFileAtDefaultLocation(): void
{
$command = $this->getCommand('/project/var/build/contao-ide');

$tester = new CommandTester($command);
$tester->execute([]);

$this->assertSame(Command::SUCCESS, $tester->getStatusCode());
$this->assertStringContainsString('The namespace lookup file was written to "var/build/contao-ide/ide-twig.json".', $tester->getDisplay());
}

public function testWritesFileToCustomLocation(): void
{
$command = $this->getCommand('/project/foo');

$tester = new CommandTester($command);
$tester->execute(['dir' => 'foo']);

$this->assertSame(Command::SUCCESS, $tester->getStatusCode());
$this->assertStringContainsString('The namespace lookup file was written to "foo/ide-twig.json".', $tester->getDisplay());
}

protected function getCommand(string $expectedWriteDir): DumpTwigIDEFileCommand
{
$namespaceLookupFileGenerator = $this->createMock(NamespaceLookupFileGenerator::class);
$namespaceLookupFileGenerator
->expects($this->once())
->method('write')
->with($expectedWriteDir)
;

return new DumpTwigIDEFileCommand(
$namespaceLookupFileGenerator,
'/project/var/build',
'/project',
);
}
}
Loading
Loading
0