Skip to content

babel-plugin-oxc-coverage: Trojan-horse adoption track for the Jest / nyc / Cypress / CRA world #39

@BartWaardenburg

Description

@BartWaardenburg

Why

The vitest (4.1.5+) and vite-plugin-istanbul (9.0.0+) integrations cover the modern build world. Everything else in the istanbul ecosystem still flows through babel-plugin-istanbul as a Babel plugin: nyc, Jest's default coverageProvider: 'babel', @cypress/code-coverage, storybook's webpack builder, and istanbul-instrumenter-loader.

A drop-in babel-plugin-oxc-coverage reaches that entire ring with zero downstream config changes (users can even alias it via "babel-plugin-istanbul": "npm:babel-plugin-oxc-coverage@*" in package.json).

Scope

New package (likely a separate repo under fallow-rs/, or a subpath export on oxc-coverage-instrument). Public surface:

module.exports = function babelPluginOxcCoverage(api, opts) {
  return {
    name: 'oxc-coverage',
    visitor: {
      Program: {
        exit(path, state) {
          // call instrument(source, filename, opts), then either replace the AST
          // or reassign state.file.code with the instrumented output.
        }
      }
    }
  };
};

Match babel-plugin-istanbul's options surface: include, exclude, cwd, extension, compact, useInlineSourceMaps, ignoreClassMethods, plus attaching the coverage map to state.file.metadata.coverage for downstream extractors (nyc, Jest).

Acceptance criteria

  • jest --coverage produces byte-for-byte parity coverage-final.json vs babel-plugin-istanbul on a small fixture
  • nyc mocha produces matching coverage on the same fixture
  • @cypress/code-coverage integration works through the cypress preprocessor's Babel config
  • Conformance suite runs both plugins against the 27 fixtures in tests/conformance/fixtures/ and diffs
  • Measurable speedup over babel-plugin-istanbul on large files (target ≥4x; the underlying instrument() call is already 8–44x)

Open design questions

  • Separate npm package vs subpath export on oxc-coverage-instrument? Discoverability favors separate (babel-plugin-* prefix is what users search for).
  • Source map composition: the plugin should compose any incoming inline sourceMappingURL with the instrumented output so reporters resolve back to original sources without a manual remap step.
  • TypeScript via @babel/preset-typescript: document that the plugin must run after type-stripping.
  • Ordering vs other Babel plugins: trust that Program:exit is late enough for nearly all use cases, or expose an assumesIsLast: false opt-out?

Effort

Estimated 3–4 days for v0.1.0 (one JS wrapper around the existing napi binding, plus the conformance harness and CI). Pre-flight: review babel-plugin-istanbul source for the option-handling and metadata-attachment details we must mirror.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions