npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@liively/swc-jest-coverage-nestjs-plugin

v0.4.1

Published

SWC plugin to transform NestJS decorator metadata for accurate Jest coverage

Downloads

26

Readme

@liively/swc-jest-coverage-nestjs-plugin

SWC plugin that eliminates phantom coverage targets generated by NestJS decorator transpilation, giving you accurate function and branch coverage when using @swc/jest.

Problem

When SWC transpiles TypeScript decorators it generates wrapper code — arrow functions for type parameters, _ts_metadata calls for reflection — that Istanbul/Jest counts as coverable targets. These targets can never be "called" by your tests, so your coverage reports show artificially low numbers (e.g. 64% function coverage on a fully-tested resolver).

This plugin transforms the generated code at compile time so that Istanbul sees only the targets that correspond to real application logic.

Installation

npm install --save-dev @liively/swc-jest-coverage-nestjs-plugin
# or
pnpm add --save-dev @liively/swc-jest-coverage-nestjs-plugin
# or
yarn add --dev @liively/swc-jest-coverage-nestjs-plugin

Configuration

Add the plugin to your Jest SWC config (usually in jest.config.js or jest.config.ts):

// jest.config.js
module.exports = {
  transform: {
    '^.+\\.tsx?$': [
      '@swc/jest',
      {
        jsc: {
          experimental: {
            plugins: [
              ['@liively/swc-jest-coverage-nestjs-plugin', {
                // All options shown with their defaults:
                // unwrapTypeArrows: true,
                // unwrapDecoratorArrows: true,
                // simplifyMetadataTypeofs: true,
                // simplifyDesignTypeTypeofs: false,
                // stripMetadata: false,
              }],
            ],
          },
        },
      },
    ],
  },
};

Important: After installing or updating the plugin, clear the Jest cache:

npx jest --clearCache

Options

| Option | Type | Default | Description | |---|---|---|---| | unwrapTypeArrows | boolean | true | Unwrap type: () => Stringtype: String in decorator option objects | | unwrapDecoratorArrows | boolean | true | Unwrap ResolveField(() => String)ResolveField(String) in decorator call arguments | | simplifyMetadataTypeofs | boolean | true | Simplify typeof guard conditionals in design:paramtypes metadata to Object | | simplifyDesignTypeTypeofs | boolean | false | Simplify typeof guard conditionals in design:type metadata to Object | | stripMetadata | boolean | false | Remove _ts_metadata("design:type", ...) calls from _ts_decorate arrays |

Note: stripMetadata defaults to false because @nestjs/mongoose depends on design:type metadata at runtime for schema type inference. Only enable it if your project does not use Mongoose (or any other library that reads design:type metadata).

Note: simplifyDesignTypeTypeofs defaults to false because @nestjs/mongoose @Prop() uses design:type to infer schema types at runtime. Enable it only if your design:type metadata contains member-expression types (e.g. mongoose.Types.ObjectId) that generate phantom branch coverage from always-true typeof guards. For mixed codebases, use per-file overrides to enable this selectively.

Per-File Overrides

You can apply different options to different files using overrides, similar to ESLint's override syntax. Each override specifies glob patterns and config options to apply when a file matches:

// jest.config.js
module.exports = {
  transform: {
    '^.+\\.tsx?$': [
      '@swc/jest',
      {
        jsc: {
          experimental: {
            plugins: [
              ['@liively/swc-jest-coverage-nestjs-plugin', {
                simplifyDesignTypeTypeofs: false,
                overrides: [
                  {
                    files: [
                      '**/venue.model*',
                      '**/user.model*',
                      '**/role.model*',
                    ],
                    config: {
                      simplifyDesignTypeTypeofs: true,
                    },
                  },
                ],
              }],
            ],
          },
        },
      },
    ],
  },
};

Behavior:

  • Glob syntax supports *, **, {a,b}, and ? patterns
  • Later overrides take precedence when multiple rules match the same file
  • Only specified fields in an override are applied; unspecified fields inherit from the base config
  • If SWC doesn't provide a filename (unlikely in practice), overrides are skipped and the base config is used
  • Windows backslash paths are normalized to forward slashes before matching

How It Works

The plugin applies up to four transforms on _ts_decorate([ ... ]) call sites:

1. Unwrap decorator arrow arguments (unwrapDecoratorArrows)

// Before — Istanbul counts the arrow as a coverable function
(0, _graphql.Query)(() => Menu)

// After — no phantom function target
(0, _graphql.Query)(Menu)

2. Unwrap type property arrows (unwrapTypeArrows)

// Before
_ts_param(0, (0, _graphql.Args)('id', { type: () => String }))

// After
_ts_param(0, (0, _graphql.Args)('id', { type: String }))

3. Simplify design:paramtypes typeof guards (simplifyMetadataTypeofs)

// Before — Istanbul counts the ternary as 2 branches, only 1 is covered
_ts_metadata("design:paramtypes", [
    typeof Express === "undefined" || typeof Express.Multer === "undefined" || typeof Express.Multer.File === "undefined" ? Object : Express.Multer.File
])

// After — no phantom branch target
_ts_metadata("design:paramtypes", [Object])

4. Simplify design:type typeof guards (simplifyDesignTypeTypeofs)

// Before — same phantom branch problem for member-expression types
_ts_metadata("design:type", typeof mongoose === "undefined" || typeof mongoose.Types === "undefined" || typeof mongoose.Types.ObjectId === "undefined" ? Object : mongoose.Types.ObjectId)

// After
_ts_metadata("design:type", Object)

Warning: This replaces the runtime type with Object, which may break libraries that read design:type metadata (e.g. @nestjs/mongoose @Prop()). Only enable this if you know your design:type values are not used at runtime, or if the affected properties already specify the type explicitly in the decorator options.

5. Strip metadata calls (stripMetadata)

// Before
_ts_decorate([
    (0, _graphql.Query)(),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [Object]),
    _ts_metadata("design:returntype", Promise)
], Resolver.prototype, "method", null);

// After
_ts_decorate([
    (0, _graphql.Query)()
], Resolver.prototype, "method", null);

Only "simple" arrows are unwrapped — the body must be an identifier (String), member expression (SomeModule.Type), or array expression ([String]). Complex arrows with block bodies are left untouched to avoid changing runtime behavior.

Compatibility

| Dependency | Version | |---|---| | @swc/core | >= 1.15.0 (swc_core v50 plugin ABI) | | Node.js | >= 18 | | Jest | >= 29 with @swc/jest |

swc_core version compatibility

| Plugin version | swc_core | @swc/core | |---|---|---| | 0.1.x | 50 | >= 1.15.0 |

Development

# Run tests
cargo test

# Build WASM (debug)
cargo build --target wasm32-wasip1

# Build WASM (release)
bash build.sh

Adding test fixtures

Each fixture is a directory under tests/fixture/ containing:

  • input.js — the SWC-transpiled code to transform
  • output.js — the expected output after transformation
  • config.json (optional) — plugin options to use instead of defaults

License

MIT