Skip to content

Export trailing Outputs comments as snippet metadata - #297

Open
adamziel wants to merge 10 commits into
masterfrom
codex/inline-output-json
Open

Export trailing Outputs comments as snippet metadata#297
adamziel wants to merge 10 commits into
masterfrom
codex/inline-output-json

Conversation

@adamziel

@adamziel adamziel commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Core PR WordPress/wordpress-develop#13267 replaces a separate expected-output fence with a trailing output comment.

This parser removes that comment from runnable PHP and exports its value through the expected_output string field. A strpos() fast path skips parsing when no marker exists. Candidate snippets pass through nikic/php-parser's emulative lexer, which normalizes token shapes across supported PHP versions without requiring each fenced example to form a complete AST. Only trailing, standalone T_COMMENT tokens beginning with // Outputs are metadata. The same text inside strings, heredocs, block comments, inline comments after code, or text outside PHP remains program text.

Output formats

Literal one-line output

echo esc_html( "<egg>" );
// Outputs: <egg>

Everything after // Outputs: is literal output. Quotes and other punctuation have no special meaning.

{
  "code": "echo esc_html( \"<egg>\" );",
  "expected_output": "<egg>"
}

Literal multiline output

print_r( array( "fruit" => "apple" ) );
// Outputs:
// Array
// (
//     [fruit] => apple
// )
//

An empty // Outputs: starts a multiline block. Each following // is one output line. One space after // is the comment delimiter; further indentation is output.

Empty final comments preserve final newlines. Quotes remain literal:

// Outputs:
// first
// "second "
//

This exports "first\n\"second \"\n".

JSON-encoded output

echo "done ";
// Outputs (JSON-encoded): "done "

// Outputs (JSON-encoded): requires one JSON string. Use it when otherwise invisible trailing whitespace, tabs, escaped quotes, or several encoded newlines must be explicit:

// Outputs (JSON-encoded): "first\nsecond \n\n"

The format is selected by the header, never by the output text. Unicode can remain literal in the DocBlock, including // Outputs (JSON-encoded): "✅ Complete ".

The old expected-output fence form is removed. Those fences are now ordinary Markdown and do not set expected_output. Output metadata must use one of the trailing comment forms above. The exported JSON shape stays the same, so consumers continue to receive expected_output as a string.

Testing

The expanded unit tests cover literal one-line and multiline output, literal quotes, indentation, trailing spaces, one and several final newlines, Unicode, valid JSON escapes, malformed JSON, non-string JSON values, non-final comments, strings, heredocs, block comments, same-line comments, text after a PHP closing tag, and the removal of expected-output fence handling.

@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Corpus diff

4 hunks, +4 -6 lines, over WordPress 7.1, parser at 0926d54 (base) vs 40d6833 (PR head, merged into base). Every hunk must be intended and explained in the PR. Download corpus.diff.

corpus.diff (40 lines)
--- base
+++ head
@@ -979310,7 +979310,7 @@
                         "arguments": [],
                         "doc": {
                             "description": "Generator for a foreach loop to step through each class name for the matched tag.",
-                            "long_description": "<p>This generator function is designed to be used inside a \"foreach\" loop.<\/p> <!-- wp-parser-code-snippet:0 -->",
+                            "long_description": "<p>This generator function is designed to be used inside a \"foreach\" loop.<\/p> <!-- wp-parser-code-snippet:0 --> <pre><code class=\"language-expected-output\">string(4) \"free\"\nstring(5) \"&lt;egg&gt;\"\nstring(7) \"lang-en\"<\/code><\/pre>",
                             "tags": [
                                 {
                                     "name": "since",
@@ -979321,8 +979321,7 @@
                             "code_snippets": [
                                 {
                                     "type": "php-code-snippet",
-                                    "code": "<?php\nrequire '\/wordpress\/wp-load.php';\n$p = WP_HTML_Processor::create_fragment( \"<div class='free &lt;egg&gt;\\tlang-en'>\" );\n$p->next_tag();\nforeach ( $p->class_list() as $class_name ) {\n  var_dump( $class_name );\n}",
-                                    "expected_output": "string(4) \"free\"\nstring(5) \"<egg>\"\nstring(7) \"lang-en\""
+                                    "code": "<?php\nrequire '\/wordpress\/wp-load.php';\n$p = WP_HTML_Processor::create_fragment( \"<div class='free &lt;egg&gt;\\tlang-en'>\" );\n$p->next_tag();\nforeach ( $p->class_list() as $class_name ) {\n  var_dump( $class_name );\n}"
                                 }
                             ]
                         },
@@ -982601,7 +982600,7 @@
                         "arguments": [],
                         "doc": {
                             "description": "Generator for a foreach loop to step through each class name for the matched tag.",
-                            "long_description": "<p>This generator function is designed to be used inside a \"foreach\" loop.<\/p> <!-- wp-parser-code-snippet:0 -->",
+                            "long_description": "<p>This generator function is designed to be used inside a \"foreach\" loop.<\/p> <!-- wp-parser-code-snippet:0 --> <pre><code class=\"language-expected-output\">string(4) \"free\"\nstring(5) \"&lt;egg&gt;\"\nstring(7) \"lang-en\"<\/code><\/pre>",
                             "tags": [
                                 {
                                     "name": "since",
@@ -982618,8 +982617,7 @@
                             "code_snippets": [
                                 {
                                     "type": "php-code-snippet",
-                                    "code": "<?php\nrequire '\/wordpress\/wp-load.php';\n$p = new WP_HTML_Tag_Processor( \"<div class='free &lt;egg&gt;\\tlang-en'>\" );\n$p->next_tag();\nforeach ( $p->class_list() as $class_name ) {\n  var_dump( $class_name );\n}",
-                                    "expected_output": "string(4) \"free\"\nstring(5) \"<egg>\"\nstring(7) \"lang-en\""
+                                    "code": "<?php\nrequire '\/wordpress\/wp-load.php';\n$p = new WP_HTML_Tag_Processor( \"<div class='free &lt;egg&gt;\\tlang-en'>\" );\n$p->next_tag();\nforeach ( $p->class_list() as $class_name ) {\n  var_dump( $class_name );\n}"
                                 }
                             ]
                         },

@adamziel
adamziel requested a review from sirreal August 31, 2026 16:08
@adamziel
adamziel requested a review from dmsnell August 31, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant