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
11,551 changes: 11,551 additions & 0 deletions php-transformer/src/HtmlToBlocks/HtmlCompilation.php

Large diffs are not rendered by default.

11,534 changes: 10 additions & 11,524 deletions php-transformer/src/HtmlToBlocks/HtmlTransformer.php

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions php-transformer/tests/unit/author-selector-semantics.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

require dirname(__DIR__, 2) . '/vendor/autoload.php';

use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlCompilation;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlTransformer;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\Style\AuthorStyleAnalysis;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\Style\CssSelectorMatcher;
Expand Down Expand Up @@ -616,16 +617,16 @@
$third = $instance->transform('<style>.cta:hover{color:red}</style><p>Read <span class="cta">this</span>.</p>')->toArray();
$assert(str_contains($css($third), 'blocks-engine-richtext-') && ! str_contains($css($third), '> :where(.wp-block-button__link)'), 'repeated selector text resolves against each transform source DOM');

$applicabilityTransformer = new HtmlTransformer();
$applicabilityTransformer->transform('<style>.absent *{color:red}.present,.missing{padding:1rem}</style><div class="present">Present</div>');
$applicabilitySession = (new ReflectionClass($applicabilityTransformer))->getProperty('session')->getValue($applicabilityTransformer);
$applicabilityCompilation = new HtmlCompilation();
$applicabilityCompilation->transform('<style>.absent *{color:red}.present,.missing{padding:1rem}</style><div class="present">Present</div>');
$applicabilitySession = (new ReflectionClass($applicabilityCompilation))->getProperty('session')->getValue($applicabilityCompilation);
$applicableRules = $applicabilitySession->authorStyleAnalysis()?->styleRules() ?? array();
$applicableSelectors = array_column(array_merge(...array_column($applicableRules, 'selectors')), 'selector');
$assert(array('.present') === $applicableSelectors, 'the installed page-matching graph omits selectors whose required source signals are absent');

$unmatchableTransformer = new HtmlTransformer();
$unmatchableTransformer->transform('<style>.card:before{content:""}.card::after{content:""}.card p::before{content:""}.card{color:red}</style><div class="card"><p>Copy</p></div>');
$unmatchableSession = (new ReflectionClass($unmatchableTransformer))->getProperty('session')->getValue($unmatchableTransformer);
$unmatchableCompilation = new HtmlCompilation();
$unmatchableCompilation->transform('<style>.card:before{content:""}.card::after{content:""}.card p::before{content:""}.card{color:red}</style><div class="card"><p>Copy</p></div>');
$unmatchableSession = (new ReflectionClass($unmatchableCompilation))->getProperty('session')->getValue($unmatchableCompilation);
$unmatchableIndex = $unmatchableSession->authorStyleAnalysis()?->styleRuleCandidateIndex() ?? array();
$indexedAuthorSelectors = array();
foreach ( array( 'universal', 'ids', 'classes', 'tags', 'attributes' ) as $bucket ) {
Expand Down
5 changes: 3 additions & 2 deletions php-transformer/tests/unit/block-style-support-conversion.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

require dirname(__DIR__, 2) . '/vendor/autoload.php';

use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlCompilation;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlTransformer;
use Automattic\BlocksEngine\PhpTransformer\VisualParity\StaticStyleParityRunner;
use Automattic\BlocksEngine\PhpTransformer\VisualParity\StaticStyleParityComparator;
Expand Down Expand Up @@ -363,8 +364,8 @@
$assert(! isset($paintAttrs['style']['background-position']) && ! isset($paintAttrs['style']['background-size']), '41: background layer controls stay out of block style attrs', json_encode($paintAttrs['style'] ?? array()));

// Style resolution moved to StyleResolver under #242.
$styleResolverProperty = new ReflectionProperty(HtmlTransformer::class, 'styleResolver');
$paintRules = $styleResolverProperty->getValue(new HtmlTransformer())->stylesheetAnalysis($paintCss)['static'];
$styleResolverProperty = new ReflectionProperty(HtmlCompilation::class, 'styleResolver');
$paintRules = $styleResolverProperty->getValue(new HtmlCompilation())->stylesheetAnalysis($paintCss)['static'];
$paintDeclarations = $paintRules[0]['declarations'] ?? array();

$assert(($paintDeclarations['background'] ?? '') === 'radial-gradient(circle at 20% 10%,rgba(255,255,255,.9),rgba(255,255,255,0) 38%),linear-gradient(180deg,#fff,#f5efe4)', '42: radial and layered backgrounds survive safe CSS resolution', json_encode($paintDeclarations));
Expand Down
9 changes: 9 additions & 0 deletions php-transformer/tests/unit/html-transformer-session-state.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@
$sessionReflection = new ReflectionClass(HtmlTransformerSession::class);
$transformerReflection = new ReflectionClass(HtmlTransformer::class);
$assert(array() === $sessionReflection->getProperties(ReflectionProperty::IS_PUBLIC), 'Transform session state must remain encapsulated behind typed lifecycle APIs.');
$transformerProperties = array_map(
static fn (ReflectionProperty $property): string => $property->getName(),
$transformerReflection->getProperties()
);
sort($transformerProperties);
$assert(
array('analysisCache', 'runtime') === $transformerProperties,
'HtmlTransformer must remain a stateless facade over immutable shared inputs.'
);
foreach ( array('__get', '__set', '__isset') as $magicAccessor ) {
$assert(! $transformerReflection->hasMethod($magicAccessor), 'HtmlTransformer must not delegate state through ' . $magicAccessor . '.');
}
Expand Down
13 changes: 7 additions & 6 deletions php-transformer/tests/unit/media-text-pattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

require dirname(__DIR__, 2) . '/vendor/autoload.php';

use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlCompilation;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlTransformer;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\Patterns\MediaTextPattern;
use Automattic\BlocksEngine\PhpTransformer\WordPress\Runtime;
Expand Down Expand Up @@ -944,17 +945,17 @@ static function (string $name, array $attrs, array $innerBlocks, ?DOMElement $so
$assertContains('has-media-on-the-right', (string) ($roundTrip['innerHTML'] ?? ''), 'Round-trip save shape restores right class.');

// Media-text style resolution memoizes by the shared presentation cache key.
$memoizedTransformer = new HtmlTransformer();
$memoizedCompilation = new HtmlCompilation();
$memoizedElement = $elementFromHtml('<section style="display:flex"><img src="memo.jpg"><div><p>Memo</p></div></section>');
// Style resolution moved to StyleResolver under #242; reach it through the
// transformer's collaborator rather than reflecting on the transformer.
$styleResolverProperty = new ReflectionProperty(HtmlTransformer::class, 'styleResolver');
$memoizedResolver = $styleResolverProperty->getValue($memoizedTransformer);
$sessionProperty = new ReflectionProperty(HtmlTransformer::class, 'session');
// run-scoped compilation collaborator rather than the public facade.
$styleResolverProperty = new ReflectionProperty(HtmlCompilation::class, 'styleResolver');
$memoizedResolver = $styleResolverProperty->getValue($memoizedCompilation);
$sessionProperty = new ReflectionProperty(HtmlCompilation::class, 'session');
$firstMediaStyle = $memoizedResolver->mediaTextPresentationStyle($memoizedElement);
$memoizedElement->setAttribute('style', 'display:grid');
$secondMediaStyle = $memoizedResolver->mediaTextPresentationStyle($memoizedElement);
$presentationCache = $sessionProperty->getValue($memoizedTransformer)->presentationResolutionCache();
$presentationCache = $sessionProperty->getValue($memoizedCompilation)->presentationResolutionCache();
$mediaStyleCache = $presentationCache->mediaTextStyles;
$presentationKey = $presentationCache->elementKey($memoizedElement);
$assertSame('display:flex', $firstMediaStyle, 'Media-text presentation style resolves initial authored style.');
Expand Down
15 changes: 7 additions & 8 deletions php-transformer/tests/unit/navigation-author-rule-memory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

require dirname(__DIR__, 2) . '/vendor/autoload.php';

use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlTransformer;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlCompilation;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\Style\AuthorStyleAnalysis;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\Style\CssSelectorMatcher;

$transformer = new HtmlTransformer();
$reflection = new ReflectionClass($transformer);
$compilation = new HtmlCompilation();
$reflection = new ReflectionClass($compilation);
$css = '@keyframes inert{' . str_repeat('x', 32 * 1024 * 1024) . '}'
. '@media (min-width:1px){.menu li a:hover{color:#123456}}';
$document = new DOMDocument();
Expand All @@ -19,7 +19,7 @@
if ( ! $body instanceof DOMElement ) {
throw new RuntimeException('Author style fixture did not produce a body element.');
}
$session = $reflection->getProperty('session')->getValue($transformer);
$session = $reflection->getProperty('session')->getValue($compilation);
$authorStyles = new AuthorStyleAnalysis($css, $css, array(), $body);
$authorStyles->installStyleRules(array(array(
'order' => 0,
Expand All @@ -34,10 +34,9 @@
$session->installAuthorStyleAnalysis($authorStyles);

// Author-rule collection moved to NavigationStyleProjector. Reach it through
// the transformer's collaborator so this still exercises the real wiring —
// including the context closure that resolves the running transform's session
// state — rather than a projector built in isolation.
$projector = $reflection->getProperty('navigationStyleProjector')->getValue($transformer);
// the compilation collaborator so this still exercises the real run-scoped
// wiring rather than a projector built in isolation.
$projector = $reflection->getProperty('navigationStyleProjector')->getValue($compilation);
$collect = ( new ReflectionClass($projector) )->getMethod('navigationAuthorStyleRules');
$rules = $collect->invoke($projector);
$rule = is_array($rules) ? ($rules[0] ?? array()) : array();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

require dirname(__DIR__, 2) . '/vendor/autoload.php';

use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlCompilation;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlTransformer;
use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\Session\NavigationProjectionState;

Expand All @@ -40,7 +41,7 @@
return $css;
};

$markup = static function (HtmlTransformer $transformer, string $htmlPath) use ($cssFor): string {
$markup = static function (HtmlTransformer|HtmlCompilation $transformer, string $htmlPath) use ($cssFor): string {
$result = $transformer->transform(
(string) file_get_contents($htmlPath),
array( 'static_css' => $cssFor($htmlPath) )
Expand All @@ -66,7 +67,7 @@

// The priming document must genuinely exercise the projection path, otherwise
// the comparison above passes for the wrong reason.
$probe = new HtmlTransformer();
$probe = new HtmlCompilation();
$markup($probe, $priming);
$session = ( new ReflectionClass($probe) )->getProperty('session')->getValue($probe);
$state = $session->navigationProjectionState();
Expand All @@ -88,9 +89,10 @@
exit(1);
}

// A fresh transform must not see the writes above.
$markup($probe, $subject);
$freshState = ( new ReflectionClass($probe) )->getProperty('session')->getValue($probe)->navigationProjectionState();
// A fresh compilation must not see the writes above.
$freshProbe = new HtmlCompilation();
$markup($freshProbe, $subject);
$freshState = ( new ReflectionClass($freshProbe) )->getProperty('session')->getValue($freshProbe)->navigationProjectionState();
if ($freshState->hasTargetForControl($control) || $freshState->isSuppressed($control)) {
fwrite(STDERR, "Navigation projection isolation contract failed: state survived a transform.\n");
exit(1);
Expand Down
Loading