From 0e3a0ad8e13cef2a3a3df4ed5f6ff9decb7313cb Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Mon, 22 Jun 2026 23:02:20 -0400 Subject: [PATCH 1/2] Add materialization view helper --- php-transformer/README.md | 7 ++ .../src/StaticSite/MaterializationView.php | 74 +++++++++++++++++++ php-transformer/tests/contract/run.php | 23 ++++++ 3 files changed, 104 insertions(+) create mode 100644 php-transformer/src/StaticSite/MaterializationView.php diff --git a/php-transformer/README.md b/php-transformer/README.md index 6055012..4b02750 100644 --- a/php-transformer/README.md +++ b/php-transformer/README.md @@ -27,6 +27,7 @@ PHP Transformer does not own product workflows such as importer admin screens, u - `HtmlToBlocks` - low-level HTML to core block transforms. - `FormatBridge` - declared-format normalization and format-to-format conversion. - `ArtifactCompiler` - generated artifact bundle normalization and compilation. +- `StaticSite` - product-neutral projections for static-site materialization planning. - `WordPress` - runtime adapters around WordPress functions. - `Contract` - shared result envelopes and diagnostics. @@ -39,6 +40,7 @@ Consumers should treat these classes and interface as the public entrypoints for - `FormatBridge\FormatBridge` - normalizes and converts declared `html`, `markdown`, and serialized `blocks` content through `convertResult()`. - `FormatBridge\FormatAdapterInterface` - adapter contract for adding formats to `FormatBridge` when a consumer genuinely needs a package-level extension point. - `ArtifactCompiler\ArtifactCompiler` - normalizes generated website artifact bundles into the shared result envelope, including block markup, source reports, assets, components, documents, and block type artifacts. +- `StaticSite\MaterializationView` - validates a `TransformerResult` object or canonical result array and returns a stable product-neutral array view for importer planning. - `WordPress\Runtime` - adapter for WordPress functions used by the transformer when running inside or outside WordPress. The remaining classes in `src/HtmlToBlocks`, `src/FormatBridge`, and `src/ArtifactCompiler` are implementation details. Concrete bundled adapters, registries, normalizers, and factories may change as the bridge expands. @@ -49,6 +51,7 @@ The remaining classes in `src/HtmlToBlocks`, `src/FormatBridge`, and `src/Artifa use Automattic\BlocksEngine\PhpTransformer\ArtifactCompiler\ArtifactCompiler; use Automattic\BlocksEngine\PhpTransformer\FormatBridge\FormatBridge; use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlTransformer; +use Automattic\BlocksEngine\PhpTransformer\StaticSite\MaterializationView; $htmlResult = (new HtmlTransformer())->transform('

Hello

', array( 'source' => 'fixture:home-html', @@ -65,6 +68,8 @@ $formatResult = (new FormatBridge())->convertResult('# Hello', 'markdown', 'bloc $artifactResult = (new ArtifactCompiler())->compile(array( 'generated_html' => '

Hello

', ))->toArray(); + +$materialization = (new MaterializationView())->fromResult($artifactResult); ``` ### WordPress Plugin Usage @@ -110,6 +115,8 @@ The result envelope includes generic `metrics` for wrapper reporting: `input_byt `source_reports.conversion_report` exposes a compact generic projection for wrappers that previously reconstructed report slices from lower-level result fields. It includes fallback diagnostics, sanitized fallback context, event attribute projections, source/selector summaries, asset references, navigation candidates, presentation and structure signals, and metrics. `source_reports.materialization_plan` exposes generic site-structure planning rows for routes, navigation links, and menus using source paths, target paths/slugs, titles/labels, parent/source relations, order, and kind. These reports remain product-neutral: callers still own route rewrites, media imports, theme assembly, navigation entity creation, visual repair policy, and acceptance gates. +Consumers that need a single importer-facing projection should use `StaticSite\MaterializationView::fromResult()` instead of reprojecting `TransformerResult` manually. The view validates the canonical result envelope and exposes `result_schema`, `status`, `artifact_summary`, `materialization_plan`, `compiled_site`, `assets`, `documents`, `block_markup`, `blocks`, `block_types`, `components`, `diagnostics`, `provenance`, and `conversion_report`. It does not perform WordPress writes or encode product-specific import policy. + `HtmlTransformer` preserves syntax-highlight spans inside `
` when they use safe inline tags and bounded attributes, while plain code remains escaped as text. Figure-wrapped testimonials and quote shapes are normalized to core quote or pullquote blocks with attribution from `cite`, `footer`, or `figcaption` content.
 
 Use `FormatBridge::convertResult()` for format conversions and unsupported source or target format diagnostics:
diff --git a/php-transformer/src/StaticSite/MaterializationView.php b/php-transformer/src/StaticSite/MaterializationView.php
new file mode 100644
index 0000000..854d13c
--- /dev/null
+++ b/php-transformer/src/StaticSite/MaterializationView.php
@@ -0,0 +1,74 @@
+
+     */
+    public function fromResult(array|object $result): array
+    {
+        $data = $this->resultArray($result);
+        TransformerResult::assertCanonicalEnvelope($data);
+
+        $sourceReports = $data['source_reports'];
+        $materializationPlan = ( new MaterializationPlanBuilder() )->fromResult($data);
+
+        return array(
+            'schema'               => self::SCHEMA,
+            'result_schema'        => $data['schema'],
+            'status'               => $data['status'],
+            'artifact_summary'     => $this->arrayValue($sourceReports, 'artifact'),
+            'materialization_plan' => $materializationPlan,
+            'compiled_site'        => $this->arrayValue($sourceReports, 'compiled_site'),
+            'assets'               => $data['assets'],
+            'documents'            => $data['documents'],
+            'block_markup'         => $data['serialized_blocks'],
+            'blocks'               => $data['blocks'],
+            'block_types'          => $data['block_types'],
+            'components'           => $data['components'],
+            'diagnostics'          => $data['diagnostics'],
+            'provenance'           => $data['provenance'],
+            'conversion_report'    => $this->arrayValue($sourceReports, 'conversion_report'),
+        );
+    }
+
+    /**
+     * @return array
+     */
+    private function resultArray(array|object $result): array
+    {
+        if ( $result instanceof TransformerResult ) {
+            return $result->toArray();
+        }
+
+        if ( is_array($result) ) {
+            return $result;
+        }
+
+        if ( is_callable(array($result, 'toArray')) ) {
+            $data = $result->toArray();
+            if ( is_array($data) ) {
+                return $data;
+            }
+        }
+
+        throw new InvalidArgumentException('Materialization view expects a TransformerResult, result array, or object with toArray().');
+    }
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    private function arrayValue(array $data, string $key): array
+    {
+        return is_array($data[$key] ?? null) ? $data[$key] : array();
+    }
+}
diff --git a/php-transformer/tests/contract/run.php b/php-transformer/tests/contract/run.php
index a75f65d..685d271 100644
--- a/php-transformer/tests/contract/run.php
+++ b/php-transformer/tests/contract/run.php
@@ -9,6 +9,7 @@
 use Automattic\BlocksEngine\PhpTransformer\FormatBridge\FormatBridge;
 use Automattic\BlocksEngine\PhpTransformer\HtmlToBlocks\HtmlTransformer;
 use Automattic\BlocksEngine\PhpTransformer\Path\ArtifactPath;
+use Automattic\BlocksEngine\PhpTransformer\StaticSite\MaterializationView;
 use Automattic\BlocksEngine\PhpTransformer\StaticSite\MaterializationPlanBuilder;
 
 if ( ! function_exists('serialize_blocks') ) {
@@ -315,6 +316,28 @@ function serialize_blocks(array $blocks): string
 $assert('css-font-face' === ($fontCompiledAsset['references'][0]['context'] ?? ''), 'compiled site assets expose structured reference metadata');
 $assert('css-font-face' === ($fontPlanAsset['references'][0]['context'] ?? ''), 'materialization plan assets preserve structured reference metadata');
 
+$materializationView = ( new MaterializationView() )->fromResult($staticSite);
+$assert(MaterializationView::SCHEMA === ($materializationView['schema'] ?? ''), 'materialization view exposes its own schema');
+$assert(TransformerResult::SCHEMA === ($materializationView['result_schema'] ?? ''), 'materialization view exposes transformer result schema');
+$assert($staticSite['status'] === ($materializationView['status'] ?? ''), 'materialization view exposes result status');
+$assert($staticSite['source_reports']['artifact'] === ($materializationView['artifact_summary'] ?? null), 'materialization view exposes artifact summary');
+$assert($staticPlan === ($materializationView['materialization_plan'] ?? null), 'materialization view exposes materialization plan');
+$assert($staticSite['source_reports']['compiled_site'] === ($materializationView['compiled_site'] ?? null), 'materialization view exposes compiled site report');
+$assert($staticSite['assets'] === ($materializationView['assets'] ?? null), 'materialization view exposes assets');
+$assert($staticSite['documents'] === ($materializationView['documents'] ?? null), 'materialization view exposes documents');
+$assert($staticSite['serialized_blocks'] === ($materializationView['block_markup'] ?? null), 'materialization view exposes block markup');
+$assert($staticSite['blocks'] === ($materializationView['blocks'] ?? null), 'materialization view exposes blocks');
+$assert($staticSite['block_types'] === ($materializationView['block_types'] ?? null), 'materialization view exposes block types');
+$assert($staticSite['components'] === ($materializationView['components'] ?? null), 'materialization view exposes components');
+$assert($staticSite['diagnostics'] === ($materializationView['diagnostics'] ?? null), 'materialization view exposes diagnostics');
+$assert($staticSite['provenance'] === ($materializationView['provenance'] ?? null), 'materialization view exposes provenance');
+$assert($staticSite['source_reports']['conversion_report'] === ($materializationView['conversion_report'] ?? null), 'materialization view exposes conversion report');
+
+$objectMaterializationView = ( new MaterializationView() )->fromResult($compiler->compile(array('generated_html' => '

Object

'))); +$assert('success' === ($objectMaterializationView['status'] ?? ''), 'materialization view accepts TransformerResult objects'); +$assert('index.html' === ($objectMaterializationView['materialization_plan']['entry_path'] ?? ''), 'materialization view exposes plans from TransformerResult objects'); +assertThrows(static fn () => ( new MaterializationView() )->fromResult((object) array('status' => 'success')), 'Materialization view expects a TransformerResult, result array, or object with toArray().'); + $neutralPlan = ( new MaterializationPlanBuilder() )->fromCompiledSite( array( 'products' => array( From 4bb47e3a6ef1f693041aca9ffce2d77247ee7837 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Mon, 22 Jun 2026 23:09:27 -0400 Subject: [PATCH 2/2] Align CSS asset fixture status --- .../fixtures/parity/artifact-css-import-font-references.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php-transformer/tests/fixtures/parity/artifact-css-import-font-references.json b/php-transformer/tests/fixtures/parity/artifact-css-import-font-references.json index 9aad590..38c1483 100644 --- a/php-transformer/tests/fixtures/parity/artifact-css-import-font-references.json +++ b/php-transformer/tests/fixtures/parity/artifact-css-import-font-references.json @@ -46,7 +46,7 @@ } }, "expect": [ - { "path": "status", "assert": "equals", "value": "success" }, + { "path": "status", "assert": "equals", "value": "success_with_warnings" }, { "path": "source_reports.artifact.asset_references", "assert": "count", "count": 4 }, { "path": "source_reports.artifact.asset_references.1.selector", "assert": "equals", "value": "css:@import(1)" }, { "path": "source_reports.artifact.asset_references.1.context", "assert": "equals", "value": "css-import" },