Skip to content

fix: strip pseudo inline placeholder from string/heredoc/nowdoc output - #2530

Draft
Dextheking1 wants to merge 2 commits into
prettier:mainfrom
Dextheking1:fix/2087-inline-placeholder-in-strings
Draft

Dextheking1 wants to merge 2 commits into
prettier:mainfrom
Dextheking1:fix/2087-inline-placeholder-in-strings

Conversation

@Dextheking1

@Dextheking1 Dextheking1 commented Sep 24, 2026 •

Copy link
Copy Markdown

Fixes #2087

parser.mjs injects ___PSEUDO_INLINE_PLACEHOLDER___ into the source text for top-level ?>\n<? sequences (workaround for glayzzle/php-parser#170). When a heredoc, nowdoc, or string literal happened to contain that sequence, the sentinel leaked into the formatted output, corrupting the string contents:

  const liftDataWithInlineRanges = <<<EOD
  <?xml version="1.0" encoding="UTF-8" ?>
- ___PSEUDO_INLINE_PLACEHOLDER___<?oxygen RNGSchema="lift.rng" type="xml"?>
+ <?oxygen RNGSchema="lift.rng" type="xml"?>

The inline printer already stripped the sentinel; the string (plain and encapsed) and nowdoc printers printed node.raw/node.value verbatim, so they now strip it too via a shared PSEUDO_INLINE_PLACEHOLDER constant.

Tests: new tests/heredoc fixture (heredoc, nowdoc, and plain-string cases, placeholder leaked before, gone after); full suite 104 suites / 598 tests green.

parser.mjs injects ___PSEUDO_INLINE_PLACEHOLDER___ into the source text for
top-level ?>\n<? sequences. When a heredoc/nowdoc/string happened to contain
that sequence, the sentinel leaked into the formatted output, corrupting the
string contents.

Fixes prettier#2087
@mreiden

mreiden commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Thanks for this — I've been running it locally and the output is right. One thing you may want to add: the new tests/heredoc fixture fails under AST_COMPARE=1 (yarn test:node with the env var set, as CONTRIBUTING suggests):

- Expected  - 2
+ Received  + 2
  "value": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>
- ___PSEUDO_INLINE_PLACEHOLDER___<?oxygen RNGSchema=\"lift.rng\" type=\"xml\"?>
- ___PSEUDO_INLINE_PLACEHOLDER___<?blueprint schema=\"lift.rng\"?>
+ <?oxygen RNGSchema=\"lift.rng\" type=\"xml\"?>
+ <?blueprint schema=\"lift.rng\"?>

Not a bug in the fix: the "expected" AST comes from parsing the source after parser.mjs injected the sentinel, so it still contains it, while the reformatted output (correctly) doesn't. Stripping ___PSEUDO_INLINE_PLACEHOLDER___ from string/encapsed/nowdoc values in clean.mjs would make the comparison hold.

parser.mjs injects ___PSEUDO_INLINE_PLACEHOLDER___ into the source text for
top-level ?> newline <? sequences. When it lands inside string, heredoc or
nowdoc values, the AST parsed from the original source keeps the sentinel
while the formatted output does not, so AST_COMPARE fails. Strip it from
string and nowdoc values in clean.mjs. Heredoc parts are string nodes, so
they are covered too.
@Dextheking1

Copy link
Copy Markdown
Author

Good catch, thanks. Added the strip to clean.mjs for string and nowdoc values (heredoc parts are string nodes, so they are covered too). Verified: AST_COMPARE=1 yarn test:node passes, 102 suites / 1174 tests, and the plain suite is green too (596 tests).

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.

___PSEUDO_INLINE_PLACEHOLDER___ added to EOD string

2 participants