Skip to content
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

[FEATURE] Add MigrateAddPageTSConfigToPageTsConfigFileRector #4229

Merged
merged 1 commit into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/v13/typo3-130.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,5 @@
$rectorConfig->singleton(\Ssch\TYPO3Rector\TYPO313\v0\UseStrictTypesInExtbaseActionControllerRector::class);
$rectorConfig->rule(\Ssch\TYPO3Rector\TYPO313\v0\IntroduceCapabilitiesBitSetRector::class);
$rectorConfig->rule(\Ssch\TYPO3Rector\TYPO313\v0\SubstituteItemFormElIDRector::class);
$rectorConfig->rule(\Ssch\TYPO3Rector\TYPO313\v0\MigrateAddPageTSConfigToPageTsConfigFileRector::class);
};
173 changes: 173 additions & 0 deletions rules/TYPO313/v0/MigrateAddPageTSConfigToPageTsConfigFileRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector\TYPO313\v0;

use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\NodeTraverser;
use PHPStan\Type\ObjectType;
use Rector\PhpParser\Node\Value\ValueResolver;
use Rector\Rector\AbstractRector;
use Ssch\TYPO3Rector\ComposerExtensionKeyResolver;
use Ssch\TYPO3Rector\Contract\FilesystemInterface;
use Ssch\TYPO3Rector\Filesystem\FilesFinder;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @changelog https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/13.0/Deprecation-101799-ExtensionManagementUtilityaddPageTSConfig.html
* @see \Ssch\TYPO3Rector\Tests\Rector\v13\v0\MigrateAddPageTSConfigToPageTsConfigFileRector\MigrateAddPageTSConfigToPageTsConfigFileRectorTest
*/
final class MigrateAddPageTSConfigToPageTsConfigFileRector extends AbstractRector
{
/**
* @readonly
*/
private FilesFinder $filesFinder;

/**
* @readonly
*/
private FilesystemInterface $filesystem;

/**
* @readonly
*/
private ValueResolver $valueResolver;

/**
* @readonly
*/
private ComposerExtensionKeyResolver $composerExtensionKeyResolver;

public function __construct(FilesFinder $filesFinder, FilesystemInterface $filesystem, ValueResolver $valueResolver, ComposerExtensionKeyResolver $composerExtensionKeyResolver)
{
$this->filesFinder = $filesFinder;
$this->filesystem = $filesystem;
$this->valueResolver = $valueResolver;
$this->composerExtensionKeyResolver = $composerExtensionKeyResolver;
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Migrate method call ExtensionManagementUtility::addPageTSConfig to page.tsconfig', [
new CodeSample(
<<<'CODE_SAMPLE'
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
'@import "EXT:ppw_sitepackage/Configuration/TSconfig/*/*.tsconfig"'
);
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
// Move to file Configuration/page.tsconfig
CODE_SAMPLE
),
]);
}

/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Expression::class];
}

/**
* @param Expression $node
*/
public function refactor(Node $node)
{
$staticMethodCall = $node->expr;

if (! $staticMethodCall instanceof StaticCall) {
return null;
}

if ($this->shouldSkip($staticMethodCall)) {
return null;
}

$contentArgument = $staticMethodCall->args[0] ?? null;

if ($contentArgument === null) {
return null;
}

$contentArgumentValue = $contentArgument->value;

if (! $contentArgumentValue instanceof String_ && ! $contentArgumentValue instanceof Concat) {
return null;
}

$this->resolvePotentialExtensionKey($contentArgumentValue);

$directoryName = dirname($this->file->getFilePath());

$content = $this->valueResolver->getValue($contentArgumentValue);
$newConfigurationFile = $directoryName . '/Configuration/page.tsconfig';
if ($this->filesystem->fileExists($newConfigurationFile)) {
$this->filesystem->appendToFile($newConfigurationFile, $content . PHP_EOL);
} else {
$this->filesystem->write($newConfigurationFile, <<<CODE
{$content}

CODE
);
}

return NodeTraverser::REMOVE_NODE;
}

private function shouldSkip(StaticCall $staticMethodCall): bool
{
if (! $this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType(
$staticMethodCall,
new ObjectType('TYPO3\CMS\Core\Utility\ExtensionManagementUtility')
)) {
return true;
}

if (! $this->isName($staticMethodCall->name, 'addPageTSConfig')) {
return true;
}

return ! $this->filesFinder->isExtLocalConf($this->file->getFilePath());
}

/**
* @param Concat|String_ $contentArgumentValue
*/
private function resolvePotentialExtensionKey($contentArgumentValue): void
{
if ($contentArgumentValue instanceof String_) {
return;
}

if (! $contentArgumentValue->left instanceof Concat) {
return;
}

if (! $contentArgumentValue->left->right instanceof Variable) {
return;
}

if (! $this->isNames($contentArgumentValue->left->right, ['_EXTKEY', 'extensionKey'])) {
return;
}

$resolvedExtensionKey = $this->composerExtensionKeyResolver->resolveExtensionKey($this->file);

if ($resolvedExtensionKey === null) {
return;
}

$contentArgumentValue->left->right = new String_($resolvedExtensionKey);
}
}
37 changes: 37 additions & 0 deletions src/ComposerExtensionKeyResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector;

use Rector\ValueObject\Application\File;
use Ssch\TYPO3Rector\Contract\FilesystemInterface;

final class ComposerExtensionKeyResolver
{
/**
* @readonly
*/
private FilesystemInterface $filesystem;

public function __construct(FilesystemInterface $filesystem)
{
$this->filesystem = $filesystem;
}

public function resolveExtensionKey(File $file): ?string
{
$directoryName = dirname($file->getFilePath());
$composerJsonFile = $directoryName . '/composer.json';

if (! $this->filesystem->fileExists($composerJsonFile)) {
return null;
}

$composerJsonContent = $this->filesystem->read($composerJsonFile);

$composerJsonContentDecoded = json_decode($composerJsonContent, true);

return $composerJsonContentDecoded['extra']['typo3/cms']['extension-key'] ?? null;
}
}
4 changes: 4 additions & 0 deletions stubs/TYPO3/CMS/Core/Utility/ExtensionManagementUtility.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,8 @@ public static function allowTableOnStandardPages(string $table)
{

}

public static function addPageTSConfig(string $content): void
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import "EXT:ext_key/Configuration/TSconfig/*/*.tsconfig"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# page.tsconfig file exist
@import "EXT:ext_key/Configuration/TSconfig/*/*.tsconfig"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import "EXT:ext_key/Configuration/TSconfig/*/*.tsconfig"

@import "EXT:ext_key/Configuration/TSconfig/*/*.tsconfig"

<INCLUDE_TYPOSCRIPT: source="FILE:EXT:cray_special_extension_key/Configuration/TSconfig/Page.txt">
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Ssch\TYPO3Rector\Tests\Rector\v13\v0\MigrateAddPageTSConfigToPageTsConfigFileRector\Fixture;

$variable = 'ext_key';

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
'@import "EXT:ext_key/Configuration/TSconfig/*/*.tsconfig"'
);

?>
-----
<?php

namespace Ssch\TYPO3Rector\Tests\Rector\v13\v0\MigrateAddPageTSConfigToPageTsConfigFileRector\Fixture;

$variable = 'ext_key';

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Ssch\TYPO3Rector\Tests\Rector\v13\v0\MigrateAddPageTSConfigToPageTsConfigFileRector\Fixture;

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
'@import "EXT:ext_key/Configuration/TSconfig/*/*.tsconfig"'
);

$variable = 'ext_key';

?>
-----
<?php

namespace Ssch\TYPO3Rector\Tests\Rector\v13\v0\MigrateAddPageTSConfigToPageTsConfigFileRector\Fixture;

$variable = 'ext_key';

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Ssch\TYPO3Rector\Tests\Rector\v13\v0\MigrateAddPageTSConfigToPageTsConfigFileRector\Fixture;

use TYPO3\CMS\Core\Utility\GeneralUtility;

$variable = 'ext_key';

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
'@import "EXT:' . $variable . '/Configuration/TSconfig/*/*.tsconfig"'
sabbelasichon marked this conversation as resolved.
Show resolved Hide resolved
);

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
GeneralUtility::deprecationLog('foo')
);

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
'@import "EXT:ext_key/Configuration/TSconfig/*/*.tsconfig"'
);

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig('<INCLUDE_TYPOSCRIPT: source="FILE:EXT:' . $_EXTKEY . '/Configuration/TSconfig/Page.txt">');

?>
-----
<?php

namespace Ssch\TYPO3Rector\Tests\Rector\v13\v0\MigrateAddPageTSConfigToPageTsConfigFileRector\Fixture;

use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;

$variable = 'ext_key';

ExtensionManagementUtility::addPageTSConfig(
GeneralUtility::deprecationLog('foo')
);

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace Ssch\TYPO3Rector\Tests\Rector\v13\v0\MigrateAddPageTSConfigToPageTsConfigFileRector;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Ssch\TYPO3Rector\Contract\FilesystemInterface;

final class MigrateAddPageTSConfigToPageTsConfigFileRectorTest extends AbstractRectorTestCase
{
private FilesystemInterface $filesystem;

protected function setUp(): void
{
parent::setUp();
$this->initializeFilesystem();
}

/**
* @dataProvider provideData
*/
public function test(string $extensionFolder, ?string $existingPageTSConfigContent = null): void
{
// Arrange
$this->filesystem->write(__DIR__ . '/Fixture/' . $extensionFolder . '/composer.json', '{
"extra": {
"typo3/cms": {
"extension-key": "cray_special_extension_key"
}
}
}
');

if ($existingPageTSConfigContent !== null) {
$this->filesystem->write(
__DIR__ . '/Fixture/' . $extensionFolder . '/Configuration/page.tsconfig',
$existingPageTSConfigContent
);
}

// Act
$this->doTestFile(__DIR__ . '/Fixture/' . $extensionFolder . '/ext_localconf.php.inc');

// Assert
$content = $this->filesystem->read(__DIR__ . '/Fixture/' . $extensionFolder . '/Configuration/page.tsconfig');
self::assertStringEqualsFile(__DIR__ . '/Assertions/' . $extensionFolder . '/page.tsconfig', $content);
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}

/**
* @return Iterator<array<string>>
*/
public static function provideData(): Iterator
{
yield 'Test that new page.tsconfig is created with correct content' => ['extension1'];

yield 'Test that content is appended to existing page.tsconfig file' => [
'extension2',
'# page.tsconfig file exist',
];

yield 'Test that new page.tsconfig is created with correct content but unresolvable content cannot be migrated properly' => [
'extension3',
];
}

private function initializeFilesystem(): void
{
$this->filesystem = $this->getContainer()
->get(FilesystemInterface::class);
}
}
Loading