Skip to content
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
42 changes: 27 additions & 15 deletions .castor/qa.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
namespace qa;

use Castor\Attribute\AsOption;
use Castor\Attribute\AsRawTokens;
use Castor\Attribute\AsTask;
use Symfony\Component\Console\Input\InputOption;

use function Castor\context;
use function Castor\exit_code;
use function Castor\run;

#[AsTask(description: 'Runs all QA tasks')]
Expand Down Expand Up @@ -47,6 +48,25 @@ function install(?string $only = null): void
}
}

#[AsTask(description: 'Update tooling')]
function update(?string $only = null): void
{
$map = [
'php-cs-fixer' => fn () => run('composer update --working-dir tools/php-cs-fixer'),
'phpstan' => fn () => run('composer update --working-dir tools/phpstan'),
'phpunit' => fn () => run('composer update --working-dir tools/phpunit'),
'rector' => fn () => run('composer update --working-dir tools/rector'),
];

if ($only) {
$map = array_filter($map, fn ($key) => $key === $only, \ARRAY_FILTER_USE_KEY);
}

foreach ($map as $task) {
$task();
}
}

#[AsTask(description: 'Fix coding standards', aliases: ['cs'])]
function cs(
#[AsOption(name: 'dry-run', description: 'Do not make changes and outputs diff', mode: InputOption::VALUE_NONE)]
Expand All @@ -58,31 +78,23 @@ function cs(
$command .= ' --dry-run --diff';
}

$c = context()
->withAllowFailure(true)
;

return run($command, context: $c)->getExitCode();
return exit_code($command);
}

#[AsTask(description: 'Run the phpstan analysis', aliases: ['phpstan'])]
function phpstan(): int
{
return run('tools/phpstan/vendor/bin/phpstan analyse')->getExitCode();
return exit_code('tools/phpstan/vendor/bin/phpstan analyse -v');
}

#[AsTask(description: 'Run the phpunit tests', aliases: ['phpunit'])]
function phpunit(): int
#[AsTask(description: 'Run the phpunit tests', ignoreValidationErrors: true, aliases: ['phpunit'])]
function phpunit(#[AsRawTokens] array $rawTokens): int
{
$c = context()
->withAllowFailure(true)
;

return run('tools/phpunit/vendor/bin/simple-phpunit', context: $c)->getExitCode();
return exit_code(['tools/phpunit/vendor/bin/phpunit', ...$rawTokens]);
}

#[AsTask(description: 'Run the rector upgrade', aliases: ['rector'])]
function rector(): int
{
return run('tools/rector/vendor/bin/rector process')->getExitCode();
return exit_code('tools/rector/vendor/bin/rector process');
}
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ jobs:
strategy:
matrix:
php-versions:
- "8.1"
- "8.2"
- "8.3"
- "8.4"
- "8.5"
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php-versions }}"
tools: jolicode/castor
tools: castor

- name: Validate composer.json and composer.lock
run: composer validate --strict
Expand All @@ -49,13 +49,13 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
tools: jolicode/castor
tools: castor

- name: Install dependencies
run: castor install
Expand Down
2 changes: 1 addition & 1 deletion .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PHP81Migration' => true,
'@PHP83Migration' => true,
'@Symfony' => true,
'@Symfony:risky' => true,
'concat_space' => ['spacing' => 'one'],
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
}
},
"require": {
"php": ">=8.1",
"php": ">=8.3",
"ext-mbstring": "*",
"lib-libxml": "*",
"league/commonmark": "^2.4",
Expand Down
38 changes: 18 additions & 20 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false"
colors="true" bootstrap="vendor/autoload.php">
<php>
<ini name="error_reporting" value="-1" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[direct]=0" />
</php>
<testsuites>
<testsuite name="JoliMarkdown Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory>./</directory>
</include>
<exclude>
<directory>./vendor</directory>
</exclude>
</coverage>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/12.4/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php">
<php>
<ini name="error_reporting" value="-1"/>
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[direct]=0"/>
</php>
<testsuites>
<testsuite name="JoliMarkdown Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>./</directory>
</include>
<exclude>
<directory>./vendor</directory>
</exclude>
</source>
</phpunit>
4 changes: 4 additions & 0 deletions src/Bridge/Symfony/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@

class Configuration implements ConfigurationInterface
{
/**
* @return TreeBuilder<'array'>
*/
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('joli_markdown');

/* @phpstan-ignore class.notFound */
$treeBuilder->getRootNode()
->children()
->booleanNode('prefer_asterisk_over_underscore')
Expand Down
13 changes: 7 additions & 6 deletions src/Fixer/HtmlBlockFixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ protected function buildNodeFromDomElement(\DOMNode $element, bool $allowLtrim =

if (\count($attributes) > 0) {
// the span has attributes, so enclose its childNodes in CommonmarkContainers
$openingNode = new InlineCommonmarkContainer(sprintf(
$openingNode = new InlineCommonmarkContainer(\sprintf(
'<span%s>',
$this->outputAttributes($attributes),
));
Expand Down Expand Up @@ -292,15 +292,15 @@ protected function buildNodeFromDomElement(\DOMNode $element, bool $allowLtrim =
// try to let self-closed html tags as-is
preg_match('/^<\s*([a-z0-9-]+)(\s[^>]*)?\/>$/', $elementXml, $matches);

if (isset($matches[1]) && preg_match(sprintf('/^<%s(\s[^>]*)?\>.*<\/%s>$/', $matches[1], $matches[1]), $converted, $subMatches)) {
if (isset($matches[1]) && preg_match(\sprintf('/^<%s(\s[^>]*)?\>.*<\/%s>$/', $matches[1], $matches[1]), $converted, $subMatches)) {
if (\in_array($matches[1], ['br', 'hr', 'source'])) {
$converted = $elementXml;
} else {
$converted = $elementHtml;
}
}

if (isset($tagNameMatches[1]) || isset($matches[1]) && preg_match(sprintf('/^<%s(\s.*)?>$/', $matches[1]), $converted, $subMatches)) {
if (isset($tagNameMatches[1]) || isset($matches[1]) && preg_match(\sprintf('/^<%s(\s.*)?>$/', $matches[1]), $converted, $subMatches)) {
$attributes = [];
}
} else {
Expand Down Expand Up @@ -445,10 +445,10 @@ protected function fixAndReplace(string|array $literal, Node|array $nodes, strin
$attributes = '';

foreach ($nodes[0]->data->get('attributes') as $key => $value) {
$attributes .= sprintf(' %s="%s"', $key, Xml::escape($value));
$attributes .= \sprintf(' %s="%s"', $key, Xml::escape($value));
}

$literal = sprintf('<div%s>%s</div>', $attributes, $literal);
$literal = \sprintf('<div%s>%s</div>', $attributes, $literal);
}

$dom = new \DOMDocument();
Expand Down Expand Up @@ -498,6 +498,7 @@ protected function removeNode(Node $node): void

foreach ($newChildren as $key => $child) {
if ($child === $node) {
// @phpstan-ignore offsetAccess.nonOffsetAccessible
unset($newChildren[$key]);
}
}
Expand Down Expand Up @@ -602,7 +603,7 @@ private function fixHtmlBlock(HtmlBlock $node): ?iterable
}

if (!$isClosed) {
$this->logger->info(sprintf('<%s> tag is NOT closed', $matches[1]));
$this->logger->info(\sprintf('<%s> tag is NOT closed', $matches[1]));
}

$fixedNodes = $this->fixAndReplace($literal, $closingNodes);
Expand Down
2 changes: 1 addition & 1 deletion src/Fixer/HtmlInlineFixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private function fixHtmlInline(HtmlInline $node): ?iterable
}

if (!$isClosed) {
$this->logger->info(sprintf('<%s> tag is NOT closed', $matches[1]));
$this->logger->info(\sprintf('<%s> tag is NOT closed', $matches[1]));
}

$fixedNodes = $this->fixAndReplace(
Expand Down
2 changes: 1 addition & 1 deletion src/Fixer/ImageFixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function fix(Node $node): ?iterable

if (str_starts_with($node->getUrl(), 'http')) {
$this->logger->notice(
sprintf(
\sprintf(
'Image with absolute path found: %s',
$node->getUrl(),
)
Expand Down
2 changes: 1 addition & 1 deletion src/MarkdownFixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function __construct(
$internalDomains = $environment->getConfiguration()->get('joli_markdown/internal_domains');

if (\is_array($internalDomains) && 0 !== \count($internalDomains)) {
$internalDomainsPattern = sprintf(
$internalDomainsPattern = \sprintf(
'#^(https?)?://(%s)/?#',
implode('|', $internalDomains),
);
Expand Down
2 changes: 1 addition & 1 deletion src/Renderer/Block/ListBlockRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer): s
$content = array_map(function (string $item): string {
if (preg_match('/^LIST_BULLET_POINT/', $item)) {
// this is an item
return sprintf('%s %s',
return \sprintf('%s %s',
$this->config->get('joli_markdown/unordered_list_marker'),
mb_substr($item, 17),
);
Expand Down
2 changes: 1 addition & 1 deletion src/Renderer/Inline/TaskListItemMarkerRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ final class TaskListItemMarkerRenderer implements NodeRendererInterface
*/
public function render(Node $node, ChildNodeRendererInterface $childRenderer): string
{
return sprintf('[%s]', $node->isChecked() ? 'x' : ' ');
return \sprintf('[%s]', $node->isChecked() ? 'x' : ' ');
}
}
38 changes: 14 additions & 24 deletions tests/MarkdownFixerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
use League\CommonMark\Parser\MarkdownParser;
use League\CommonMark\Renderer\HtmlRenderer;
use League\CommonMark\Util\HtmlFilter;
use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

/**
* @internal
*
* @coversNothing
*/
#[CoversNothing()]
final class MarkdownFixerTest extends TestCase
{
private MarkdownFixer $markdownFixer;
Expand Down Expand Up @@ -86,46 +87,35 @@ protected function setUp(): void
$this->htmlRenderer = new HtmlRenderer($environment);
}

/**
* @dataProvider dataProvider
*/
public function testFixer(string $inputMarkdown, string $expectedMarkdown, string $convertedhtml, string $testName): void
#[DataProvider('dataProvider')]
public function testFixer(string $inputMarkdown, string $expectedMarkdown, string $convertedHtml, string $testName): void
{
$this->assertFixMarkdown($inputMarkdown, $expectedMarkdown, $testName);
}

/**
* @dataProvider dataProvider
*/
public function testRenderer(string $inputMarkdown, string $expectedMarkdown, string $expectedhtml, string $testName): void
#[DataProvider('dataProvider')]
public function testRenderer(string $inputMarkdown, string $expectedMarkdown, string $expectedHtml, string $testName): void
{
$this->assertConvertToHtml($expectedMarkdown, $expectedhtml, $testName);
$this->assertConvertToHtml($expectedMarkdown, $expectedHtml, $testName);
}

/**
* @return array
*/
public function dataProvider()
public static function dataProvider(): iterable
{
$ret = [];

foreach (glob(__DIR__ . '/data/*-in.md') as $markdownFile) {
$testName = basename((string) $markdownFile, '-in.md');
$inputMarkdown = file_get_contents($markdownFile);
$expectedMarkdown = file_get_contents(__DIR__ . '/data/' . $testName . '-out.md');
$expectedhtml = file_get_contents(__DIR__ . '/data/' . $testName . '-out.html');
$expectedHtml = file_get_contents(__DIR__ . '/data/' . $testName . '-out.html');

yield [$inputMarkdown, $expectedMarkdown, $expectedhtml, $testName];
yield [$inputMarkdown, $expectedMarkdown, $expectedHtml, $testName];
}

return $ret;
}

protected function assertFixMarkdown(string $inputMarkdown, string $expectedMarkdown, string $testName): void
{
$fixedMarkdown = $this->markdownFixer->fix($inputMarkdown);

static::assertSame($expectedMarkdown, $fixedMarkdown, sprintf('Unexpected result for "%s" test', $testName));
static::assertSame($expectedMarkdown, $fixedMarkdown, \sprintf('Unexpected result for "%s" test', $testName));

$lastMarkdown = $fixedMarkdown;
$i = 0;
Expand All @@ -136,15 +126,15 @@ protected function assertFixMarkdown(string $inputMarkdown, string $expectedMark

++$i;
}
static::assertSame($lastMarkdown, $previousMarkdown, sprintf('Unexpected multi-pass result for "%s" test', $testName));
static::assertSame($lastMarkdown, $previousMarkdown, \sprintf('Unexpected multi-pass result for "%s" test', $testName));
}

protected function assertConvertToHtml(string $markdown, string $expectedHtml, string $testName): void
{
$document = $this->docParser->parse($markdown);
$actualHtml = $this->htmlRenderer->renderDocument($document)->getContent();

$failureMessage = sprintf('Unexpected result for "%s" test', $testName);
$failureMessage = \sprintf('Unexpected result for "%s" test', $testName);
$failureMessage .= "\n=== markdown ===============\n" . $markdown;
$failureMessage .= "\n=== expected ===============\n" . $expectedHtml . '(strlen=' . mb_strlen($expectedHtml) . ')';
$failureMessage .= "\n=== got ====================\n" . $actualHtml . '(strlen=' . mb_strlen($actualHtml) . ')';
Expand Down
2 changes: 1 addition & 1 deletion tests/data/instagram-out.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<blockquote class="instagram-media" data-instgrm-captioned="true" data-instgrm-version="7" style="background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);">
<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-version="7" style="background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);">
<div style="padding:8px;"> <div style=" background:#F8F8F8; line-height:0; margin-top:40px; padding:50.187734668335416% 0; text-align:center; width:100%;"> <div style=" background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAMUExURczMzPf399fX1+bm5mzY9AMAAADiSURBVDjLvZXbEsMgCES5/P8/t9FuRVCRmU73JWlzosgSIIZURCjo/ad+EQJJB4Hv8BFt+IDpQoCx1wjOSBFhh2XssxEIYn3ulI/6MNReE07UIWJEv8UEOWDS88LY97kqyTliJKKtuYBbruAyVh5wOHiXmpi5we58Ek028czwyuQdLKPG1Bkb4NnM+VeAnfHqn1k4+GPT6uGQcvu2h2OVuIf/gWUFyy8OWEpdyZSa3aVCqpVoVvzZZ2VTnn2wU8qzVjDDetO90GSy9mVLqtgYSy231MxrY6I2gGqjrTY0L8fxCxfCBbhWrsYYAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-22px; width:44px;"></div></div> <p style=" margin:8px 0 0 0; padding:0 4px;"> <a href="https://www.instagram.com/p/BVIAcA7F3zo/" rel="nofollow noopener" style=" color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;" target="_blank">Some text</a></p> <p style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;">A publication shared by JoliCode (@jolicode) le <time datetime="2017-06-09T16:13:16+00:00" style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px;">9 Juin 2017 à 9h13 PDT</time></p></div>
</blockquote>
<script async defer src="//platform.instagram.com/en_US/embeds.js"></script>
Loading