Skip to content

prettier-ignore-start/end leaks ignoreRegion state across files, causing subsequent files to be emptied #146

@onedot-webagency

Description

@onedot-webagency

Description

When using {# prettier-ignore-start #} / {# prettier-ignore-end #} in a Twig file, unrelated files processed later in the same Prettier run are
written as empty (0 bytes). This is a data-loss bug when used with --write.

Root Cause

printer.js uses module-level variables to track ignore state:

  // printer.js L72-74
  let originalSource = "";
  let ignoreRegion = false;
  let ignoreNext = false;

These variables are never reset between files. If ignoreRegion is not properly cleared during AST traversal of one file (e.g. because prettier-
ignore-end is not visited as a standalone comment node),
it leaks into every subsequent file. In the print function, when ignoreRegion is true and canGetSubstringForNode() fails, the fallback is return
"" (L124), resulting in empty output.

Reproduction

Plugin version: 0.16.3
Prettier version: 3.8.1

File A (listing.html.twig):

  {% sw_extends '@storefront/storefront/component/product/listing.html.twig' %}

  {% block element_product_listing_col %}
      {# prettier-ignore-start #}
      <div
          class="page-{{ currentPage }}"
          data-offset="{{ searchResult.criteria.extensions.additionalOffset.value
            - searchResult.criteria.extensions.pageOffset.value }}"
          data-has-next-page="{{ searchResult.total > searchResult.criteria.offset + (searchResult.elements is iterable
            ? searchResult.elements|length : 0) }}"
      >
      {# prettier-ignore-end #}
          <p>Content</p>
      </div>
  {% endblock %}

File B (other.html.twig) — any valid Twig file processed after File A:

  {% sw_extends '@storefront/storefront/page/account/sidebar.html.twig' %}

  {% block page_account_sidebar_link_subscriptions %}
  {% endblock %}

Steps:

  1. Place both files in a project using @zackad/prettier-plugin-twig
  2. Run npx prettier --write "**/*.twig"
  3. File B is now empty (0 bytes)

Expected Behavior

prettier-ignore-start/end should only affect the region within the same file. Other files must not be affected.

Suggested Fix

Reset state when entering a new file's root node in printer.js:

   const print = (path, options, print) => {
       const node = path.getValue();
       const nodeType = node.constructor.name;

       // Try to get the entire original source from AST root
       if (node[ORIGINAL_SOURCE]) {
           originalSource = node[ORIGINAL_SOURCE];
  +        ignoreRegion = false;
  +        ignoreNext = false;
       }

This ensures module-level state is reset at the start of each file's print cycle.

Workaround

Add affected files to .prettierignore to prevent them from being processed.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions