Skip to content

Cannot use istanbul ignore comments for generated code #2138

Open

Description

@CreativeTechGuy

Describe the bug

When using Solid and testing our app with coverage reporting enabled (powered by istanbul/nyc), there are some branches/functions which are uncovered, but they are not branches which exist in our code, instead they are generated by Solid. Because these code paths are generated, we cannot place a /* istanbul ignore next */ comment before the appropriate section because it doesn't exist anywhere in our source.

A few cases where this occurs (I'm sure there's others):

  • Show/Match components - If the match is never used, there's an unused function because of the get children() method which got generated
  • Refs - It generates a ternary with typeof _ref$ === "function" as the condiiton. Which in most cases will always be true/false so that means there's a branch of the code which never gets hit.

All of these result in an extra uncovered function here, an extra uncovered branch there. And there's no way we can add the appropriate comments before this code to ignore it.

Your Example Website or App

https://playground.solidjs.com/anonymous/7b917606-9c75-4695-b669-accb486afc92

Steps to Reproduce the Bug or Issue

N/A

Expected behavior

When Solid is generating the runtime code, it should relocate the comments appropriately so they keep the same meaning that they have in the source.

Source:

{/* istanbul ignore next */}
<Match when={condition()}>
    <div>Hello</div>
</Match>

Generated:

_$createComponent(Show, {
  get when() {
    return condition();
  },
  /* istanbul ignore next */
  get children() {
    return _tmpl$();
  }
})

Source:

let ref;
return <div ref={ref}>Hello</div>

Generated: (This should always add the appropriate ignore comments since only one branch will ever be hit.)

let ref;
return (() => {
  var _el$ = _tmpl$();
  var _ref$ = ref;
  /* istanbul ignore next */
  typeof _ref$ === "function" ? _$use(_ref$, _el$) : ref = _el$;
  return _el$;
})();

Screenshots or Videos

No response

Platform

  • OS: N/A
  • Browser: N/A
  • Version: 1.8.16

Additional context

It's also impossible currently to write our own plugin to do this since comments will get totally deleted during compilation when placed in certain spots of the JSX.

For example, this input:

function Counter() {
  let ref;
  /* istanbul ignore next -- 1 */
  return (
    <>
      {/* istanbul ignore next -- 2 */}
      <div ref={ref}>Hi</div>
    </>
  );
}

Gets transformed into: (the second comment is just totally lost so we cannot even attempt to move it with our own plugin after Solid is done compiling)

function Counter() {
  let ref;
  /* istanbul ignore next -- 1 */
  return (() => {
    var _el$ = _tmpl$();
    var _ref$ = ref;
    typeof _ref$ === "function" ? _$use(_ref$, _el$) : ref = _el$;
    return _el$;
  })();
}

This is a unique problem with Solid which doesn't exist with many other frameworks because Solid generates a lot of code rather than just calling functions from the Solid library. If these same bits of code were instead unconditional function calls to code in node_modules, this wouldn't be an issue.

Activity

  1. ryansolid commented on Apr 19, 2024

    @ryansolid
    Member

    Yeah this is a tricky one. Source maps have also been challenging. We've made some improvements but due to the need for function wrappers/special handling of ref those things need to be inline. Like above _$use is the helper function but to keep references we can't pull that all in.

    It's an interesting problem in that tooling that operates on source (ie not compiled code like in IDEs like TS etc) aren't going to have this problem. I wonder how this works in stuff like Svelte/Vue. Admittedly other than trying to keep references in compilation we generally don't go out of our way and try to let Babel do its thing.

  2. CreativeTechGuy commented on Apr 20, 2024

    @CreativeTechGuy
    Author

    Oh yeah I definitely have had trouble with source maps when debugging before too now that you mention it.

    Is there any solution to something like this? I'm trying to get my organization to buy in to rewriting our app in Solid and it's going to be a tough sell if there's no workaround for this (aside from just ignoring it).

    But you are right, it's not a single tool problem but something much bigger.

  3. nickshiro commented on Sep 7, 2026

    @nickshiro

    I've already started working on this problem; here's my plan: preserve “istanbul ignore” comments from JSX during compilation, automatically mark generated ref forks, add tests for the Babel and Oxc compilers to ensure their output remains compatible.

  4. ryansolid commented on Sep 8, 2026

    @ryansolid
    Member

    Ruling, so the plan above doesn't build further than it needs to (full reasoning on #3301):

    • Yes to preserving istanbul ignore / c8 ignore comments the author writes in JSX through to the generated output — in both the Babel plugin and the Oxc compiler, in parity.
    • No to the compiler automatically marking its own generated branches (ref forks etc.) with a coverage tool's pragma. Generated-branch attribution is the coverage tool's job — v8 coverage with source-map/AST-aware remapping already lands these on the JSX — and we don't want vendor pragmas emitted into everyone's output.

    — Claude via Cursor

  5. ryansolid commented on Sep 30, 2026

    @ryansolid
    Member

    Status update: part of this landed on `next` in #3301 (`3c1f809`) and ships in 2.0.0-rc.14.

    What's covered now: a coverage pragma written inside a component's JSX children — `{/* istanbul ignore next /}` or `{/ c8 ignore next */}`, block comments only — is carried onto the `children` getter the compiler emits. The Babel plugin and the native compiler behave identically across DOM, SSR, and universal output.

    Still open:

    • Pragma before the component. In the example here the pragma sits before ``, so it lands on the parent's `children` getter rather than on `Match`'s own.
    • Pragmas inside fragments aren't carried.
    • SSR hoisted props: when a nested component's children are hoisted into a `get()` descriptor, the comment isn't carried (same in both compilers).
    • Generated code (e.g. the ref-dispatch ternary): the compiler won't inject coverage pragmas into its own output — only pragmas the author wrote are preserved.

    Leaving this open while the maintainer decides how to handle the remaining cases.

    — Claude via Cursor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions