parse( '' . $inner . '' ); } /** Marks every divi/button; refuses opaque blocks, like the real strategies must never be offered one. */ private static function touchButtons(): NodeRewrite { return new class implements NodeRewrite { public function rewrite(Block $block): ?array { if ($block->isOpaque()) { throw new \LogicException('An opaque block was offered to rewrite().'); } return $block->name() === 'divi/button' ? $block->attrs() + ['touched' => true] : null; } public function notes(Block $block, string $nodeId): array { return ['Hinweis ' . $nodeId]; } public function concernsInstance(Block $instance): bool { return GlobalInstance::effectiveName($instance) === 'divi/button'; } }; } public function testChangesBlocksAndReportsThem(): void { $document = self::document( '' . '' ); $result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document)); self::assertSame([ ['id' => 's0.r0.c0.m0', 'module' => 'divi/button', 'label' => 'Kaufen'], ['id' => 's0.r0.c0.m2', 'module' => 'divi/button', 'label' => ''], ], $result['changed']); self::assertSame(['Hinweis s0.r0.c0.m0', 'Hinweis s0.r0.c0.m2'], $result['warnings']); self::assertSame([], $result['skipped']); self::assertSame(2, substr_count(Serializer::document($document), '"touched":true')); } public function testNothingToDoChangesNothing(): void { $document = self::document(''); $before = Serializer::document($document); $result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document)); self::assertSame(['changed' => [], 'warnings' => [], 'skipped' => []], $result); self::assertSame($before, Serializer::document($document)); } public function testGlobalInstancesAreSkippedWithTheLibraryEntry(): void { $document = self::document( '' . '' ); $before = Serializer::document($document); $result = (new TreeRewrite(self::touchButtons(), true))->apply(NodeIndex::build($document)); self::assertSame([], $result['changed']); self::assertSame( [['id' => 's0.r0.c0.g0', 'reason' => 'globales Modul – im Bibliothekseintrag 1058 ändern']], $result['skipped'] ); self::assertSame($before, Serializer::document($document), 'instances are never rewritten'); } /** Ruling P13, fail closed: without $revealLibraryIds the reason names no library ID. */ public function testGlobalInstanceReasonHidesTheLibraryIdByDefault(): void { $document = self::document( '' ); $result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document)); self::assertSame( [['id' => 's0.r0.c0.g0', 'reason' => 'globales Modul – im Divi-Builder ändern']], $result['skipped'] ); } public function testBlocksWithUnreadableAttributesAreSkippedToo(): void { $document = self::document(''); $result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document)); self::assertSame( [['id' => 's0.r0.c0.m0', 'reason' => 'Attribute nicht lesbar – im Divi-Builder prüfen']], $result['skipped'] ); } public function testAGlobalLayoutWithoutLibraryEntryHasItsOwnReason(): void { $document = self::document(''); $result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document)); self::assertSame( [['id' => 's0.r0.c0.g0', 'reason' => 'globales Modul ohne Bibliothekseintrag – im Divi-Builder prüfen']], $result['skipped'] ); } public function testAReportsLeftoversStrategyListsUnchangedBlocksAsSkipped(): void { $embedded = 'Ab ' . VariableDetachRewriteTest::ref('gvid-radius0001') . ' Rundung'; $text = static fn (string $value): string => ''; $document = self::document( $text($embedded) . $text(VariableDetachRewriteTest::ref('gvid-radius0001')) . '' ); $result = (new TreeRewrite(new VariableDetachRewrite('gvid-radius0001', '8px', 'numbers'))) ->apply(NodeIndex::build($document)); self::assertSame(['s0.r0.c0.m1'], array_column($result['changed'], 'id')); self::assertSame(['s0.r0.c0.m0'], array_column($result['skipped'], 'id'), 'embedded only: reported'); self::assertSame([], $result['warnings']); } }