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
2 changes: 1 addition & 1 deletion php-transformer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ if ('failed' === $result['status']) {

## Artifact Compiler Fallbacks

The artifact compiler accepts loose generated-site bundles and normalizes them into an explicit result envelope. HTML entries are preserved as `core/html` serialized block markup, Markdown falls back to `core/html` when a Markdown adapter is not loaded, and MDX support is partial: source documents are preserved while imports and JSX component references are exposed as inspectable metadata and warnings.
The artifact compiler accepts loose generated-site bundles and normalizes them into an explicit result envelope. Safe HTML entries are compiled through `HtmlTransformer` into native serialized block markup, Markdown falls back to `core/html` when a Markdown adapter is not loaded, and MDX support is partial: source documents are preserved while imports and JSX component references are exposed as inspectable metadata and warnings.

Unsupported or unsafe artifact inputs are reported through diagnostics instead of hidden best-effort behavior. Empty, absolute, or root-escaping paths are rejected; oversized files are ignored according to the source report limits; and a bundle with neither an HTML entry nor source documents fails with `missing_entry_html`.

Expand Down
21 changes: 1 addition & 20 deletions php-transformer/src/ArtifactCompiler/ArtifactCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private function compileEntryBlocks(string $html, string $entryPath, array $file
);
}

if ( '' === trim($html) || ! $this->entryHtmlReferencesImageAsset($html, $entryPath, $files) ) {
if ( '' === trim($html) ) {
return array(
'blocks' => array(),
'serialized_blocks' => '',
Expand All @@ -159,25 +159,6 @@ private function compileEntryBlocks(string $html, string $entryPath, array $file
);
}

/**
* @param array<int, array<string, mixed>> $files
*/
private function entryHtmlReferencesImageAsset(string $html, string $entryPath, array $files): bool
{
if ( ! preg_match_all('/<img\s+[^>]*src\s*=\s*(["\'])([^"\']+)\1/i', $html, $matches) ) {
return false;
}

foreach ( $matches[2] as $src ) {
$asset = $this->findAssetByHtmlReference((string) $src, $entryPath, $files);
if ( is_array($asset) && str_starts_with((string) ($asset['mime_type'] ?? ''), 'image/') && $this->isSafeImageAsset($asset) ) {
return true;
}
}

return false;
}

/**
* @param array<int, array<string, mixed>> $files
*/
Expand Down
5 changes: 3 additions & 2 deletions php-transformer/tests/contract/run.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,13 @@ function serialize_blocks(array $blocks): string
$assert(ArtifactCompiler::INPUT_SCHEMA === ($simple['source_reports']['artifact']['schema'] ?? ''), 'artifact report exposes canonical site artifact schema');
$assert(ArtifactCompiler::INPUT_SCHEMA === ($simple['source_reports']['artifact']['original_schema'] ?? ''), 'canonical site artifact input schema is accepted and preserved');
$assert('index.html' === ($simple['source_reports']['artifact']['entry_path'] ?? ''), 'generated HTML becomes an index entry');
$assert(str_contains((string) $simple['serialized_blocks'], '<!-- wp:html -->'), 'HTML is preserved as serialized block markup');
$assert(str_contains((string) $simple['serialized_blocks'], '<!-- wp:heading'), 'artifact HTML is transformed into native serialized block markup');
$assert(! str_contains((string) $simple['serialized_blocks'], '<!-- wp:html -->'), 'artifact HTML does not fall back to raw HTML when transformer-safe');
$assert('hero' === ($simple['components'][0]['name'] ?? ''), 'component candidates are exposed');
$assert(! array_key_exists('legacy_mapping', $simple), 'artifact result omits compatibility-only legacy mapping');
$assert(strlen('<main><article data-component="Hero"><h1>Hello artifact</h1></article></main>') === ($simple['metrics']['input_bytes'] ?? null), 'artifact metrics expose input bytes');
$assert(strlen((string) $simple['serialized_blocks']) === ($simple['metrics']['output_bytes'] ?? null), 'artifact metrics expose output bytes');
$assert(0 === ($simple['metrics']['block_count'] ?? null), 'artifact metrics expose block count');
$assert(2 === ($simple['metrics']['block_count'] ?? null), 'artifact metrics expose nested block count');
$assert(0 === ($simple['metrics']['fallback_count'] ?? null), 'artifact metrics expose fallback count');
$assert(0 === ($simple['metrics']['diagnostic_count'] ?? null), 'artifact metrics expose diagnostic count');
$assert(is_float($simple['metrics']['transform_duration_ms'] ?? null), 'artifact metrics expose transform duration');
Expand Down
13 changes: 10 additions & 3 deletions php-transformer/tests/fixtures/parity/artifact-generated-html.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
{
"schema": "blocks-engine/php-transformer/parity-fixture/v1",
"name": "artifact-generated-html-entry",
"description": "Compiles generated HTML artifact input into the shared transformer result shape.",
"description": "Compiles generated static HTML artifact input without images into native block markup through the HTML transformer.",
"source_reference": {
"repo": "php-transformer",
"path": "tests/fixtures/parity/artifact-generated-html.json",
"notes": "Covers the artifact compiler contract smoke path."
"notes": "Covers the artifact compiler default HTML transform path when entry markup has no local image references."
},
"operation": "artifact_compiler.compile",
"input": {
"artifact": {
"generated_html": "<main><article data-component=\"Hero\"><h1>Hello artifact</h1></article></main>"
}
},
"expected_blocks": [
{ "path": "blocks.0", "name": "core/group" },
{ "path": "blocks.0.innerBlocks.0", "name": "core/heading", "attrs": { "content": "Hello artifact", "level": 1 } }
],
"expected_fallbacks": [],
"expect": [
{ "path": "schema", "assert": "equals", "value": "blocks-engine/php-transformer/result/v1" },
{ "path": "status", "assert": "equals", "value": "success" },
{ "path": "source_reports.artifact.entry_path", "assert": "equals", "value": "index.html" },
{ "path": "components.0.name", "assert": "equals", "value": "hero" },
{ "path": "serialized_blocks", "assert": "contains", "value": "<!-- wp:html -->" },
{ "path": "serialized_blocks", "assert": "contains", "value": "<!-- wp:group -->" },
{ "path": "serialized_blocks", "assert": "contains", "value": "<!-- wp:heading {\"content\":\"Hello artifact\",\"level\":1} -->" },
{ "path": "serialized_blocks", "assert": "contains", "value": "<h1>Hello artifact</h1>" },
{ "path": "serialized_blocks", "assert": "not_contains", "value": "<!-- wp:html -->" },
{ "path": "source_reports.artifact.html.element_count", "assert": "equals", "value": 3 },
{ "path": "source_reports.conversion_report.metrics.fallback_count", "assert": "equals", "value": 0 },
{ "path": "provenance.0.source_format", "assert": "equals", "value": "artifact" }
Expand Down
Loading