From 02d14684e0f8727da53f4ef8b55d72ced52d25e3 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 15 Nov 2025 13:23:11 +0100 Subject: [PATCH 1/9] require php 8.4 --- .github/workflows/ci.yml | 10 ++++------ CHANGELOG.md | 6 ++++++ composer.json | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 189105d..779f162 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,13 +4,11 @@ on: [push, pull_request] jobs: blackbox: - uses: innmind/github-workflows/.github/workflows/black-box-matrix.yml@main + uses: innmind/github-workflows/.github/workflows/black-box-matrix.yml@next coverage: - uses: innmind/github-workflows/.github/workflows/coverage-matrix.yml@main + uses: innmind/github-workflows/.github/workflows/coverage-matrix.yml@next secrets: inherit psalm: - uses: innmind/github-workflows/.github/workflows/psalm-matrix.yml@main + uses: innmind/github-workflows/.github/workflows/psalm-matrix.yml@next cs: - uses: innmind/github-workflows/.github/workflows/cs.yml@main - with: - php-version: '8.2' + uses: innmind/github-workflows/.github/workflows/cs.yml@next diff --git a/CHANGELOG.md b/CHANGELOG.md index 6142933..8ab6e4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased] + +### Changed + +- Requires PHP `8.4` + ## 8.0.0 - 2025-06-01 ### Added diff --git a/composer.json b/composer.json index 705a5d0..0a6bb76 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "issues": "http://github.com/Innmind/XML/issues" }, "require": { - "php": "~8.2", + "php": "~8.4", "innmind/immutable": "~5.15", "innmind/filesystem": "~8.1" }, From 5ffc1e3ee623d0959f302cef0319d04c50489afc Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 15 Nov 2025 13:27:56 +0100 Subject: [PATCH 2/9] use the new Dom api to parse contents --- src/Reader.php | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Reader.php b/src/Reader.php index 7c5073d..ff97aad 100644 --- a/src/Reader.php +++ b/src/Reader.php @@ -30,20 +30,15 @@ public function __invoke(Content $content): Attempt return Attempt::error(new \RuntimeException('Empty content')); } - $xml = new \DOMDocument; - /** @psalm-suppress ImpureMethodCall */ - $success = $xml->loadXML( - $content, - \LIBXML_ERR_ERROR | \LIBXML_NOWARNING | \LIBXML_NOERROR, - ); - - if (!$success) { - return Attempt::error(new \RuntimeException('Failed to load xml content')); + try { + $xml = \Dom\XMLDocument::createFromString( + $content, + \LIBXML_ERR_ERROR | \LIBXML_NOWARNING | \LIBXML_NOERROR, + ); + } catch (\Throwable $e) { + return Attempt::error($e); } - /** @psalm-suppress ImpureMethodCall */ - $xml->normalizeDocument(); - return ($this->translate)($xml); } From ae1c8aad6e2493b4e66171aa91f6294d7e02b754 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 15 Nov 2025 13:50:25 +0100 Subject: [PATCH 3/9] remove support for old DOM api --- src/Translator.php | 83 +++++-------------- .../CharacterDataTranslatorTest.php | 3 +- .../NodeTranslator/CommentTranslatorTest.php | 3 +- .../NodeTranslator/DocumentTranslatorTest.php | 3 +- .../NodeTranslator/ElementTranslatorTest.php | 3 +- .../EntityReferenceTranslatorTest.php | 14 +++- .../NodeTranslator/TextTranslatorTest.php | 3 +- .../NodeTranslator/Visitor/AttributesTest.php | 6 +- .../NodeTranslator/Visitor/ChildrenTest.php | 6 +- tests/Translator/TranslatorTest.php | 50 ++++------- 10 files changed, 55 insertions(+), 119 deletions(-) diff --git a/src/Translator.php b/src/Translator.php index 49a8a14..3a5d5e4 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -31,11 +31,9 @@ private function __construct( } /** - * @psalm-suppress UndefinedClass Since the package still supports PHP 8.2 - * * @return Attempt */ - public function __invoke(\DOMNode|\Dom\Node $node): Attempt + public function __invoke(\Dom\Node $node): Attempt { return $this ->buildDocument($node) @@ -58,7 +56,6 @@ public static function of(?callable $custom = null): self } /** - * @psalm-suppress UndefinedClass Since the package still supports PHP 8.2 * @psalm-suppress TypeDoesNotContainType * @psalm-suppress MixedArgument * @psalm-suppress MixedMethodCall @@ -66,54 +63,39 @@ public static function of(?callable $custom = null): self * * @return Attempt */ - private function child(\DOMNode|\Dom\Node $node): Attempt + private function child(\Dom\Node $node): Attempt { if ( $node->nodeType === \XML_COMMENT_NODE && - ( - $node instanceof \DOMComment || - $node instanceof \Dom\Comment - ) + $node instanceof \Dom\Comment ) { return Attempt::result(Node::comment($node->data)); } if ( $node->nodeType === \XML_TEXT_NODE && - ( - $node instanceof \DOMText || - $node instanceof \Dom\Text - ) + $node instanceof \Dom\Text ) { return Attempt::result(Node::text($node->data)); } if ( $node->nodeType === \XML_CDATA_SECTION_NODE && - ( - $node instanceof \DOMCharacterData || - $node instanceof \Dom\CharacterData - ) + $node instanceof \Dom\CharacterData ) { return Attempt::result(Node::characterData($node->data)); } if ( $node->nodeType === \XML_ENTITY_REF_NODE && - ( - $node instanceof \DOMEntityReference || - $node instanceof \Dom\EntityReference - ) + $node instanceof \Dom\EntityReference ) { return Attempt::result(Node::entityReference($node->nodeName)); } if ( $node->nodeType === \XML_PI_NODE && - ( - $node instanceof \DOMProcessingInstruction || - $node instanceof \Dom\ProcessingInstruction - ) + $node instanceof \Dom\ProcessingInstruction ) { return Attempt::result(Node::processingInstruction( $node->nodeName, @@ -123,10 +105,7 @@ private function child(\DOMNode|\Dom\Node $node): Attempt if ( $node->nodeType === \XML_ELEMENT_NODE && - ( - $node instanceof \DOMElement || - $node instanceof \Dom\Element - ) + $node instanceof \Dom\Element ) { /** * @psalm-suppress ImpureFunctionCall @@ -142,11 +121,7 @@ private function child(\DOMNode|\Dom\Node $node): Attempt fn($attributes) => $this ->children( Sequence::of(...\array_values(\iterator_to_array($node->childNodes))) - ->keep( - Instance::of(\DOMNode::class)->or( - Instance::of(\Dom\Node::class), - ), - ), + ->keep(Instance::of(\Dom\Node::class)), ) ->map(static fn($children) => match ($node->childNodes->length) { 0 => Element::selfClosing($name, $attributes), @@ -168,22 +143,17 @@ private function child(\DOMNode|\Dom\Node $node): Attempt } /** - * @psalm-suppress UndefinedClass Since the package still supports PHP 8.2 * @psalm-suppress MixedArgument * @psalm-suppress MixedMethodCall * @psalm-suppress UndefinedPropertyFetch * * @return Attempt */ - private function buildDocument(\DOMNode|\Dom\Node $node): Attempt + private function buildDocument(\Dom\Node $node): Attempt { /** @psalm-suppress MixedArgumentTypeCoercion */ return Maybe::just($node) - ->keep( - Instance::of(\DOMDocument::class)->or( - Instance::of(\Dom\Document::class), - ), - ) + ->keep(Instance::of(\Dom\Document::class)) ->attempt(static fn() => new \RuntimeException('Not a document')) ->flatMap( fn($document) => self::buildVersion($document) @@ -196,11 +166,7 @@ private function buildDocument(\DOMNode|\Dom\Node $node): Attempt fn($encoding) => $this ->children( Sequence::of(...\array_values(\iterator_to_array($document->childNodes))) - ->keep( - Instance::of(\DOMNode::class)->or( - Instance::of(\Dom\Node::class), - ), - ) + ->keep(Instance::of(\Dom\Node::class)) ->exclude(static fn($child) => $child->nodeType === \XML_DOCUMENT_TYPE_NODE), ) ->map(static fn($children) => Document::of( @@ -217,13 +183,12 @@ private function buildDocument(\DOMNode|\Dom\Node $node): Attempt /** * @psalm-pure * @psalm-suppress ImpurePropertyFetch - * @psalm-suppress UndefinedClass Since the package still supports PHP 8.2 * * @return Maybe */ - private static function buildVersion(\DOMDocument|\Dom\Document $document): Maybe + private static function buildVersion(\Dom\Document $document): Maybe { - [$major, $minor] = \explode('.', $document->xmlVersion ?? ''); + [$major, $minor] = \explode('.', (string) ($document->xmlVersion ?? '')); return Version::maybe( (int) $major, @@ -234,11 +199,10 @@ private static function buildVersion(\DOMDocument|\Dom\Document $document): Mayb /** * @psalm-pure * @psalm-suppress ImpurePropertyFetch - * @psalm-suppress UndefinedClass Since the package still supports PHP 8.2 * * @return Maybe */ - private static function buildDoctype(\DOMDocumentType|\Dom\DocumentType $type): Maybe + private static function buildDoctype(\Dom\DocumentType $type): Maybe { /** @psalm-suppress MixedArgument */ return Type::maybe( @@ -249,36 +213,27 @@ private static function buildDoctype(\DOMDocumentType|\Dom\DocumentType $type): } /** - * @psalm-suppress UndefinedClass Since the package still supports PHP 8.2 * @psalm-suppress TypeDoesNotContainType * @psalm-suppress MixedArgument * * @return Attempt> */ - private static function attributes(\DOMElement|\Dom\Element $element): Attempt + private static function attributes(\Dom\Element $element): Attempt { /** @var Sequence */ $attributes = Sequence::of(); $attrs = []; - if ( - $element->attributes instanceof \DOMNamedNodeMap || - $element->attributes instanceof \Dom\NamedNodeMap - ) { + if ($element->attributes instanceof \Dom\NamedNodeMap) { /** * @psalm-suppress ImpureFunctionCall * @psalm-suppress ImpureMethodCall - * @psalm-suppress PossiblyInvalidArgument Due to \Dom\NamedNodeMap for PHP 8.2 */ $attrs = \iterator_to_array($element->attributes); } return Sequence::of(...\array_values($attrs)) - ->keep( - Instance::of(\DOMAttr::class)->or( - Instance::of(\Dom\Attr::class), - ), - ) + ->keep(Instance::of(\Dom\Attr::class)) ->sink($attributes) ->attempt( static fn($attributes, $attribute) => Attribute::maybe( @@ -297,7 +252,7 @@ private static function attributes(\DOMElement|\Dom\Element $element): Attempt /** * @psalm-suppress UndefinedDocblockClass Since the package still supports PHP 8.2 * - * @param Sequence<\DOMNode|\Dom\Node> $children + * @param Sequence<\Dom\Node> $children * * @return Attempt> */ diff --git a/tests/Translator/NodeTranslator/CharacterDataTranslatorTest.php b/tests/Translator/NodeTranslator/CharacterDataTranslatorTest.php index 07e1e9d..7aed223 100644 --- a/tests/Translator/NodeTranslator/CharacterDataTranslatorTest.php +++ b/tests/Translator/NodeTranslator/CharacterDataTranslatorTest.php @@ -13,8 +13,7 @@ class CharacterDataTranslatorTest extends TestCase { public function testTranslate() { - $document = new \DOMDocument; - $document->loadXML($xml = << XML ); diff --git a/tests/Translator/NodeTranslator/CommentTranslatorTest.php b/tests/Translator/NodeTranslator/CommentTranslatorTest.php index 09cc166..84d9505 100644 --- a/tests/Translator/NodeTranslator/CommentTranslatorTest.php +++ b/tests/Translator/NodeTranslator/CommentTranslatorTest.php @@ -13,8 +13,7 @@ class CommentTranslatorTest extends TestCase { public function testTranslate() { - $document = new \DOMDocument; - $document->loadXML($xml = << XML ); diff --git a/tests/Translator/NodeTranslator/DocumentTranslatorTest.php b/tests/Translator/NodeTranslator/DocumentTranslatorTest.php index 5f39b6e..a5a118c 100644 --- a/tests/Translator/NodeTranslator/DocumentTranslatorTest.php +++ b/tests/Translator/NodeTranslator/DocumentTranslatorTest.php @@ -14,8 +14,7 @@ class DocumentTranslatorTest extends TestCase { public function testTranslate() { - $document = new \DOMDocument; - $document->loadXML($xml = << diff --git a/tests/Translator/NodeTranslator/ElementTranslatorTest.php b/tests/Translator/NodeTranslator/ElementTranslatorTest.php index f843ad9..5a42d1b 100644 --- a/tests/Translator/NodeTranslator/ElementTranslatorTest.php +++ b/tests/Translator/NodeTranslator/ElementTranslatorTest.php @@ -14,8 +14,7 @@ class ElementTranslatorTest extends TestCase { public function testTranslate() { - $document = new \DOMDocument; - $document->loadXML($xml = << XML ); diff --git a/tests/Translator/NodeTranslator/EntityReferenceTranslatorTest.php b/tests/Translator/NodeTranslator/EntityReferenceTranslatorTest.php index 4694fed..f3b1e01 100644 --- a/tests/Translator/NodeTranslator/EntityReferenceTranslatorTest.php +++ b/tests/Translator/NodeTranslator/EntityReferenceTranslatorTest.php @@ -5,7 +5,7 @@ use Innmind\Xml\{ Translator, - Node, + Element, }; use Innmind\BlackBox\PHPUnit\Framework\TestCase; @@ -13,15 +13,21 @@ class EntityReferenceTranslatorTest extends TestCase { public function testTranslate() { + $document = \Dom\XMLDocument::createFromString($xml = << + > + XML + ); + $translate = Translator::of(); $node = $translate( - new \DOMEntityReference('gt'), + $document->childNodes->item(0), )->match( static fn($node) => $node, static fn() => null, ); - $this->assertInstanceOf(Node::class, $node); - $this->assertSame('gt', $node->content()); + $this->assertInstanceOf(Element::class, $node); + $this->assertSame(">\n", $node->asContent()->toString()); } } diff --git a/tests/Translator/NodeTranslator/TextTranslatorTest.php b/tests/Translator/NodeTranslator/TextTranslatorTest.php index 321273a..3e3bb02 100644 --- a/tests/Translator/NodeTranslator/TextTranslatorTest.php +++ b/tests/Translator/NodeTranslator/TextTranslatorTest.php @@ -13,8 +13,7 @@ class TextTranslatorTest extends TestCase { public function testTranslate() { - $document = new \DOMDocument; - $document->loadXML($xml = <<foo XML ); diff --git a/tests/Translator/NodeTranslator/Visitor/AttributesTest.php b/tests/Translator/NodeTranslator/Visitor/AttributesTest.php index dc429a6..6f056a7 100644 --- a/tests/Translator/NodeTranslator/Visitor/AttributesTest.php +++ b/tests/Translator/NodeTranslator/Visitor/AttributesTest.php @@ -11,8 +11,7 @@ class AttributesTest extends TestCase { public function testNoAttributes() { - $document = new \DOMDocument; - $document->loadXML(''); + $document = \Dom\XMLDocument::createFromString(''); $attributes = Translator::of()($document->childNodes->item(0))->match( static fn($element) => $element->attributes()->toSet(), @@ -25,8 +24,7 @@ public function testNoAttributes() public function testAttributes() { - $document = new \DOMDocument; - $document->loadXML('
'); + $document = \Dom\XMLDocument::createFromString('
'); $attributes = Translator::of()($document->childNodes->item(0))->match( static fn($element) => $element->attributes()->toSet(), diff --git a/tests/Translator/NodeTranslator/Visitor/ChildrenTest.php b/tests/Translator/NodeTranslator/Visitor/ChildrenTest.php index 67cf95e..c120a36 100644 --- a/tests/Translator/NodeTranslator/Visitor/ChildrenTest.php +++ b/tests/Translator/NodeTranslator/Visitor/ChildrenTest.php @@ -11,8 +11,7 @@ class ChildrenTest extends TestCase { public function testNoChildren() { - $document = new \DOMDocument; - $document->loadXML(''); + $document = \Dom\XMLDocument::createFromString(''); $children = Translator::of()( $document->childNodes->item(0), @@ -27,8 +26,7 @@ public function testNoChildren() public function testChildren() { - $document = new \DOMDocument; - $document->loadXML(''); + $document = \Dom\XMLDocument::createFromString(''); $children = Translator::of()( $document->childNodes->item(0), diff --git a/tests/Translator/TranslatorTest.php b/tests/Translator/TranslatorTest.php index fa3bfb4..ff5d565 100644 --- a/tests/Translator/TranslatorTest.php +++ b/tests/Translator/TranslatorTest.php @@ -13,7 +13,6 @@ }; use Innmind\Immutable\Maybe; use Innmind\BlackBox\PHPUnit\Framework\TestCase; -use PHPUnit\Framework\Attributes\DataProvider; class TranslatorTest extends TestCase { @@ -24,9 +23,23 @@ public function setUp(): void $this->translate = Translator::of(); } - #[DataProvider('documents')] - public function testTranslate($document, $xml) + public function testTranslate() { + $xml = << + + + +
+ +
+ + hey! +
+ XML; + + $document =\Dom\XMLDocument::createFromString($xml); + $node = ($this->translate)($document)->match( static fn($node) => $node, static fn() => null, @@ -143,8 +156,7 @@ public function normalize(): Element } }; $translate = Translator::of(static fn() => Maybe::just($custom)); - $document = new \DOMDocument; - $document->loadXML(''); + $document = \Dom\XMLDocument::createFromString(''); $this->assertSame( $custom, @@ -157,32 +169,4 @@ public function normalize(): Element ), ); } - - public static function documents(): iterable - { - $xml = << - - - -
- -
- - hey! -
- XML; - - $document = new \DOMDocument; - $document->loadXML($xml); - - yield '\DOMDocument' => [$document, $xml]; - - if (\PHP_VERSION_ID >= 80400) { - yield '\Dom\Document' => [ - \Dom\XMLDocument::createFromString($xml), - $xml, - ]; - } - } } From e369599f75e40e0e9e0326b834c5b12f8c50767f Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 15 Nov 2025 13:53:51 +0100 Subject: [PATCH 4/9] remove outdated psalm-suppress instructions --- src/Translator.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Translator.php b/src/Translator.php index 3a5d5e4..fe86f7e 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -56,9 +56,7 @@ public static function of(?callable $custom = null): self } /** - * @psalm-suppress TypeDoesNotContainType * @psalm-suppress MixedArgument - * @psalm-suppress MixedMethodCall * @psalm-suppress MixedPropertyFetch * * @return Attempt @@ -144,14 +142,11 @@ private function child(\Dom\Node $node): Attempt /** * @psalm-suppress MixedArgument - * @psalm-suppress MixedMethodCall - * @psalm-suppress UndefinedPropertyFetch * * @return Attempt */ private function buildDocument(\Dom\Node $node): Attempt { - /** @psalm-suppress MixedArgumentTypeCoercion */ return Maybe::just($node) ->keep(Instance::of(\Dom\Document::class)) ->attempt(static fn() => new \RuntimeException('Not a document')) @@ -213,7 +208,6 @@ private static function buildDoctype(\Dom\DocumentType $type): Maybe } /** - * @psalm-suppress TypeDoesNotContainType * @psalm-suppress MixedArgument * * @return Attempt> @@ -250,8 +244,6 @@ private static function attributes(\Dom\Element $element): Attempt } /** - * @psalm-suppress UndefinedDocblockClass Since the package still supports PHP 8.2 - * * @param Sequence<\Dom\Node> $children * * @return Attempt> From 595a4cf2b3b1d7518f875016e538841566926261 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sat, 15 Nov 2025 13:59:51 +0100 Subject: [PATCH 5/9] update dependencies --- composer.json | 10 ++++++++-- tests/DocumentTest.php | 8 ++++---- tests/Element/ElementTest.php | 20 +++++++++---------- tests/Element/SelfClosingElementTest.php | 12 +++++------ tests/ReaderTest.php | 7 ++++--- .../NodeTranslator/Visitor/AttributesTest.php | 4 ++-- .../NodeTranslator/Visitor/ChildrenTest.php | 4 ++-- tests/Translator/TranslatorTest.php | 8 ++++---- 8 files changed, 40 insertions(+), 33 deletions(-) diff --git a/composer.json b/composer.json index 0a6bb76..06fc3a2 100644 --- a/composer.json +++ b/composer.json @@ -16,8 +16,14 @@ }, "require": { "php": "~8.4", - "innmind/immutable": "~5.15", - "innmind/filesystem": "~8.1" + "innmind/immutable": "dev-next", + "innmind/filesystem": "dev-next", + "innmind/media-type": "dev-next", + "innmind/io": "dev-next", + "innmind/url": "dev-next", + "innmind/validation": "dev-next", + "innmind/ip": "dev-next", + "innmind/time-continuum": "dev-next" }, "autoload": { "psr-4": { diff --git a/tests/DocumentTest.php b/tests/DocumentTest.php index 7f3ee50..7615b10 100644 --- a/tests/DocumentTest.php +++ b/tests/DocumentTest.php @@ -147,8 +147,8 @@ public function testPrependChild() $this->assertSame($document->type(), $document2->type()); $this->assertSame($document->encoding(), $document2->encoding()); $this->assertNotSame($document->children(), $document2->children()); - $this->assertCount(3, $document->children()); - $this->assertCount(4, $document2->children()); + $this->assertSame(3, $document->children()->size()); + $this->assertSame(4, $document2->children()->size()); $this->assertSame( $node, $document2->children()->get(0)->match( @@ -211,8 +211,8 @@ public function testAppendChild() $this->assertSame($document->type(), $document2->type()); $this->assertSame($document->encoding(), $document2->encoding()); $this->assertNotSame($document->children(), $document2->children()); - $this->assertCount(3, $document->children()); - $this->assertCount(4, $document2->children()); + $this->assertSame(3, $document->children()->size()); + $this->assertSame(4, $document2->children()->size()); $this->assertEquals( $document->children()->get(0), $document2->children()->get(0), diff --git a/tests/Element/ElementTest.php b/tests/Element/ElementTest.php index 32d2a1c..6b87d07 100644 --- a/tests/Element/ElementTest.php +++ b/tests/Element/ElementTest.php @@ -76,8 +76,8 @@ public function testRemoveAttribute() $this->assertSame($node->name(), $node2->name()); $this->assertSame($node->children(), $node2->children()); $this->assertNotSame($node->attributes(), $node2->attributes()); - $this->assertCount(2, $node->attributes()); - $this->assertCount(1, $node2->attributes()); + $this->assertSame(2, $node->attributes()->size()); + $this->assertSame(1, $node2->attributes()->size()); $this->assertTrue($node->attribute('foo')->match( static fn() => true, static fn() => false, @@ -145,8 +145,8 @@ public function testReplaceAttribute() $this->assertSame($node->name(), $node2->name()); $this->assertSame($node->children(), $node2->children()); $this->assertNotSame($node->attributes(), $node2->attributes()); - $this->assertCount(2, $node->attributes()); - $this->assertCount(2, $node2->attributes()); + $this->assertSame(2, $node->attributes()->size()); + $this->assertSame(2, $node2->attributes()->size()); $this->assertTrue($node->attribute('foo')->match( static fn() => true, static fn() => false, @@ -195,8 +195,8 @@ public function testAddAttribute() $this->assertSame($node->name(), $node2->name()); $this->assertSame($node->children(), $node2->children()); $this->assertNotSame($node->attributes(), $node2->attributes()); - $this->assertCount(2, $node->attributes()); - $this->assertCount(3, $node2->attributes()); + $this->assertSame(2, $node->attributes()->size()); + $this->assertSame(3, $node2->attributes()->size()); $this->assertTrue($node->attribute('foo')->match( static fn() => true, static fn() => false, @@ -270,8 +270,8 @@ public function testPrependChild() $this->assertSame($element->name(), $element2->name()); $this->assertSame($element->attributes(), $element2->attributes()); $this->assertNotSame($element->children(), $element2->children()); - $this->assertCount(3, $element->children()); - $this->assertCount(4, $element2->children()); + $this->assertSame(3, $element->children()->size()); + $this->assertSame(4, $element2->children()->size()); $this->assertSame( $node, $element2->children()->get(0)->match( @@ -332,8 +332,8 @@ public function testAppendChild() $this->assertSame($element->name(), $element2->name()); $this->assertSame($element->attributes(), $element2->attributes()); $this->assertNotSame($element->children(), $element2->children()); - $this->assertCount(3, $element->children()); - $this->assertCount(4, $element2->children()); + $this->assertSame(3, $element->children()->size()); + $this->assertSame(4, $element2->children()->size()); $this->assertEquals( $element->children()->get(0), $element2->children()->get(0), diff --git a/tests/Element/SelfClosingElementTest.php b/tests/Element/SelfClosingElementTest.php index 5db3aaa..672518e 100644 --- a/tests/Element/SelfClosingElementTest.php +++ b/tests/Element/SelfClosingElementTest.php @@ -65,8 +65,8 @@ public function testRemoveAttribute() $this->assertSame($node->name(), $node2->name()); $this->assertTrue($node2->children()->empty()); $this->assertNotSame($node->attributes(), $node2->attributes()); - $this->assertCount(2, $node->attributes()); - $this->assertCount(1, $node2->attributes()); + $this->assertSame(2, $node->attributes()->size()); + $this->assertSame(1, $node2->attributes()->size()); $this->assertTrue($node->attribute('foo')->match( static fn() => true, static fn() => false, @@ -121,8 +121,8 @@ public function testReplaceAttribute() $this->assertSame($node->name(), $node2->name()); $this->assertTrue($node2->children()->empty()); $this->assertNotSame($node->attributes(), $node2->attributes()); - $this->assertCount(2, $node->attributes()); - $this->assertCount(2, $node2->attributes()); + $this->assertSame(2, $node->attributes()->size()); + $this->assertSame(2, $node2->attributes()->size()); $this->assertTrue($node->attribute('foo')->match( static fn() => true, static fn() => false, @@ -171,8 +171,8 @@ public function testAddAttribute() $this->assertSame($node->name(), $node2->name()); $this->assertTrue($node2->children()->empty()); $this->assertNotSame($node->attributes(), $node2->attributes()); - $this->assertCount(2, $node->attributes()); - $this->assertCount(3, $node2->attributes()); + $this->assertSame(2, $node->attributes()->size()); + $this->assertSame(3, $node2->attributes()->size()); $this->assertTrue($node->attribute('foo')->match( static fn() => true, static fn() => false, diff --git a/tests/ReaderTest.php b/tests/ReaderTest.php index 89dba5a..07f886b 100644 --- a/tests/ReaderTest.php +++ b/tests/ReaderTest.php @@ -13,7 +13,7 @@ Format, }; use Innmind\Filesystem\{ - Adapter\Filesystem, + Adapter, File, File\Content, Name, @@ -82,7 +82,8 @@ public function testReturnNothingWhenInvalidXml() public function testProcessingInstructionsAreReadCorrectly() { - $content = Filesystem::mount(Path::of('fixtures/')) + $content = Adapter::mount(Path::of('fixtures/')) + ->unwrap() ->get(Name::of('theatlantic.xml')) ->keep(Instance::of(File::class)) ->match( @@ -96,7 +97,7 @@ public function testProcessingInstructionsAreReadCorrectly() ); $this->assertInstanceOf(Document::class, $node); - $this->assertCount(2, $node->children()); + $this->assertSame(2, $node->children()->size()); $stylesheet = $node->children()->first()->match( static fn($stylesheet) => $stylesheet, static fn() => null, diff --git a/tests/Translator/NodeTranslator/Visitor/AttributesTest.php b/tests/Translator/NodeTranslator/Visitor/AttributesTest.php index 6f056a7..3d42d87 100644 --- a/tests/Translator/NodeTranslator/Visitor/AttributesTest.php +++ b/tests/Translator/NodeTranslator/Visitor/AttributesTest.php @@ -19,7 +19,7 @@ public function testNoAttributes() ); $this->assertInstanceOf(Set::class, $attributes); - $this->assertCount(0, $attributes); + $this->assertSame(0, $attributes->size()); } public function testAttributes() @@ -32,7 +32,7 @@ public function testAttributes() ); $this->assertInstanceOf(Set::class, $attributes); - $this->assertCount(2, $attributes); + $this->assertSame(2, $attributes->size()); $attributes = $attributes->toList(); $this->assertSame('bar', $attributes[0]->name()); $this->assertSame('baz', $attributes[0]->value()); diff --git a/tests/Translator/NodeTranslator/Visitor/ChildrenTest.php b/tests/Translator/NodeTranslator/Visitor/ChildrenTest.php index c120a36..cf2e950 100644 --- a/tests/Translator/NodeTranslator/Visitor/ChildrenTest.php +++ b/tests/Translator/NodeTranslator/Visitor/ChildrenTest.php @@ -21,7 +21,7 @@ public function testNoChildren() ); $this->assertInstanceOf(Sequence::class, $children); - $this->assertCount(0, $children); + $this->assertSame(0, $children->size()); } public function testChildren() @@ -36,6 +36,6 @@ public function testChildren() ); $this->assertInstanceOf(Sequence::class, $children); - $this->assertCount(2, $children); + $this->assertSame(2, $children->size()); } } diff --git a/tests/Translator/TranslatorTest.php b/tests/Translator/TranslatorTest.php index ff5d565..f3323bb 100644 --- a/tests/Translator/TranslatorTest.php +++ b/tests/Translator/TranslatorTest.php @@ -69,19 +69,19 @@ public function testTranslate() static fn() => null, ), ); - $this->assertCount(1, $node->children()); + $this->assertSame(1, $node->children()->size()); $foo = $node->children()->get(0)->match( static fn($node) => $node, static fn() => null, ); $this->assertInstanceOf(Element::class, $foo); $this->assertSame('foo', $foo->name()->toString()); - $this->assertCount(1, $foo->attributes()); + $this->assertSame(1, $foo->attributes()->size()); $this->assertSame('baz', $foo->attribute('bar')->match( static fn($attribute) => $attribute->value(), static fn() => null, )); - $this->assertCount(7, $foo->children()); + $this->assertSame(7, $foo->children()->size()); $linebreak = $foo->children()->get(0)->match( static fn($node) => $node, static fn() => null, @@ -108,7 +108,7 @@ public function testTranslate() $this->assertInstanceOf(Element::class, $div); $this->assertSame('div', $div->name()->toString()); $this->assertTrue($div->attributes()->empty()); - $this->assertCount(3, $div->children()); + $this->assertSame(3, $div->children()->size()); $linebreak = $div->children()->get(0)->match( static fn($node) => $node, static fn() => null, From 79c7830de46806f6bd9d114a345408b8a523bb45 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 16 Nov 2025 14:29:52 +0100 Subject: [PATCH 6/9] prefer the local name over the node name --- src/Translator.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Translator.php b/src/Translator.php index fe86f7e..0bc22c8 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -105,14 +105,18 @@ private function child(\Dom\Node $node): Attempt $node->nodeType === \XML_ELEMENT_NODE && $node instanceof \Dom\Element ) { + // Prefer the local name over the node name to avoid using upper + // case naming when translating html documents (see innmind/html) + $name = (string) ($node->localName ?? $node->nodeName); + /** * @psalm-suppress ImpureFunctionCall * @psalm-suppress ImpureMethodCall */ - return Name::maybe($node->nodeName) + return Name::maybe($name) ->attempt(static fn() => new \RuntimeException(\sprintf( 'Invalid node name "%s"', - $node->nodeName, + $name, ))) ->flatMap( fn($name) => self::attributes($node)->flatMap( From 23a6a6da548a0d4ac742736276ec406f50a75f2c Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 25 Jan 2026 18:33:30 +0100 Subject: [PATCH 7/9] tag dependencies --- .github/workflows/ci.yml | 8 ++++---- CHANGELOG.md | 2 ++ composer.json | 12 +++--------- src/Document.php | 2 +- tests/Element/ElementTest.php | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 779f162..2f3eecb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,11 +4,11 @@ on: [push, pull_request] jobs: blackbox: - uses: innmind/github-workflows/.github/workflows/black-box-matrix.yml@next + uses: innmind/github-workflows/.github/workflows/black-box-matrix.yml@main coverage: - uses: innmind/github-workflows/.github/workflows/coverage-matrix.yml@next + uses: innmind/github-workflows/.github/workflows/coverage-matrix.yml@main secrets: inherit psalm: - uses: innmind/github-workflows/.github/workflows/psalm-matrix.yml@next + uses: innmind/github-workflows/.github/workflows/psalm-matrix.yml@main cs: - uses: innmind/github-workflows/.github/workflows/cs.yml@next + uses: innmind/github-workflows/.github/workflows/cs.yml@main diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ab6e4b..12e5597 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Changed - Requires PHP `8.4` +- Requires `innmind/immutable:~6.0` +- Requires `innmind/filesystem:~9.0` ## 8.0.0 - 2025-06-01 diff --git a/composer.json b/composer.json index 06fc3a2..fc66a25 100644 --- a/composer.json +++ b/composer.json @@ -16,14 +16,8 @@ }, "require": { "php": "~8.4", - "innmind/immutable": "dev-next", - "innmind/filesystem": "dev-next", - "innmind/media-type": "dev-next", - "innmind/io": "dev-next", - "innmind/url": "dev-next", - "innmind/validation": "dev-next", - "innmind/ip": "dev-next", - "innmind/time-continuum": "dev-next" + "innmind/immutable": "~6.0", + "innmind/filesystem": "~9.0" }, "autoload": { "psr-4": { @@ -36,7 +30,7 @@ } }, "require-dev": { - "innmind/static-analysis": "^1.2.1", + "innmind/static-analysis": "~1.3", "innmind/coding-standard": "~2.0", "innmind/black-box": "^6.4.1" } diff --git a/src/Document.php b/src/Document.php index 50683fd..9c67f1f 100644 --- a/src/Document.php +++ b/src/Document.php @@ -153,7 +153,7 @@ private function render(\XMLWriter $writer): Sequence ), ); /** @psalm-suppress ImpureMethodCall */ - $this->type->match( + $_ = $this->type->match( static fn($type) => $writer->writeRaw($type->toString()."\n"), static fn() => null, ); diff --git a/tests/Element/ElementTest.php b/tests/Element/ElementTest.php index 6b87d07..e17eb01 100644 --- a/tests/Element/ElementTest.php +++ b/tests/Element/ElementTest.php @@ -525,7 +525,7 @@ public function testAsContentRenderingIsLazy() ->lines() ->take(2) ->map(static fn($line) => $line->str()) - ->fold(new Concat) + ->fold(Concat::monoid) ->toString(), ); $this->assertFalse($loaded); From b6ee1bd19c1066f29cc8e0ecfc4b754226e66360 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 25 Jan 2026 18:33:49 +0100 Subject: [PATCH 8/9] CS --- tests/Translator/TranslatorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Translator/TranslatorTest.php b/tests/Translator/TranslatorTest.php index f3323bb..0031765 100644 --- a/tests/Translator/TranslatorTest.php +++ b/tests/Translator/TranslatorTest.php @@ -38,7 +38,7 @@ public function testTranslate()
XML; - $document =\Dom\XMLDocument::createFromString($xml); + $document = \Dom\XMLDocument::createFromString($xml); $node = ($this->translate)($document)->match( static fn($node) => $node, From c121b37c16068bd255137e652c37de531830a458 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 25 Jan 2026 18:34:47 +0100 Subject: [PATCH 9/9] add extensive CI --- .github/workflows/extensive.yml | 12 ++++++++++++ blackbox.php | 4 ++++ 2 files changed, 16 insertions(+) create mode 100644 .github/workflows/extensive.yml diff --git a/.github/workflows/extensive.yml b/.github/workflows/extensive.yml new file mode 100644 index 0000000..257f139 --- /dev/null +++ b/.github/workflows/extensive.yml @@ -0,0 +1,12 @@ +name: Extensive CI + +on: + push: + tags: + - '*' + paths: + - '.github/workflows/extensive.yml' + +jobs: + blackbox: + uses: innmind/github-workflows/.github/workflows/extensive.yml@main diff --git a/blackbox.php b/blackbox.php index 5c3ddce..b70ed93 100644 --- a/blackbox.php +++ b/blackbox.php @@ -11,6 +11,10 @@ Application::new($argv) ->disableMemoryLimit() + ->when( + \getenv('BLACKBOX_SET_SIZE') !== false, + static fn(Application $app) => $app->scenariiPerProof((int) \getenv('BLACKBOX_SET_SIZE')), + ) ->when( \getenv('ENABLE_COVERAGE') !== false, static fn(Application $app) => $app