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
7 changes: 7 additions & 0 deletions php-transformer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.
Expand All @@ -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('<h1>Hello</h1>', array(
'source' => 'fixture:home-html',
Expand All @@ -65,6 +68,8 @@ $formatResult = (new FormatBridge())->convertResult('# Hello', 'markdown', 'bloc
$artifactResult = (new ArtifactCompiler())->compile(array(
'generated_html' => '<main><h1>Hello</h1></main>',
))->toArray();

$materialization = (new MaterializationView())->fromResult($artifactResult);
```

### WordPress Plugin Usage
Expand Down Expand Up @@ -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 `<pre><code>` 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:
Expand Down
74 changes: 74 additions & 0 deletions php-transformer/src/StaticSite/MaterializationView.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);

namespace Automattic\BlocksEngine\PhpTransformer\StaticSite;

use Automattic\BlocksEngine\PhpTransformer\Contract\TransformerResult;
use InvalidArgumentException;

final class MaterializationView
{
public const SCHEMA = 'blocks-engine/php-transformer/materialization-view/v1';

/**
* @return array<string,mixed>
*/
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<string,mixed>
*/
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<string,mixed> $data
* @return array<string,mixed>
*/
private function arrayValue(array $data, string $key): array
{
return is_array($data[$key] ?? null) ? $data[$key] : array();
}
}
23 changes: 23 additions & 0 deletions php-transformer/tests/contract/run.php
Original file line number Diff line number Diff line change
Expand Up @@ -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') ) {
Expand Down Expand Up @@ -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' => '<main><h1>Object</h1></main>')));
$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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand Down
Loading