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

@gunshi/plugin-dryrun

v0.35.1

Published

dry-run option plugin for gunshi

Readme

@gunshi/plugin-dryrun

Version InstallSize JSR

dry-run option plugin for gunshi.

This plugin provides dry-run support for CLI applications, allowing command authors to mark side-effect operations that should be skipped when users pass --dry-run.

💿 Installation

# npm
npm install --save @gunshi/plugin-dryrun

# pnpm
pnpm add @gunshi/plugin-dryrun

# yarn
yarn add @gunshi/plugin-dryrun

# deno
deno add jsr:@gunshi/plugin-dryrun

# bun
bun add @gunshi/plugin-dryrun

🚀 Usage

import { cli, defineWithTypes } from 'gunshi'
import dryrun, { pluginId as dryrunId } from '@gunshi/plugin-dryrun'

import type { DryRunExtension } from '@gunshi/plugin-dryrun'

const command = defineWithTypes<{
  extensions: {
    [dryrunId]: DryRunExtension
  }
}>()({
  name: 'deploy',
  async run(ctx) {
    const dryRun = ctx.extensions[dryrunId]

    await dryRun.run(
      async function build() {
        // build artifacts
      },
      {
        message: 'build artifacts'
      }
    )
  }
})

await cli(process.argv.slice(2), command, {
  name: 'deploy-cli',
  plugins: [
    dryrun() // Adds the --dry-run option
  ]
})

When --dry-run is passed, the wrapped operation is skipped and the message is printed through ctx.log():

[dryrun] build artifacts

[!IMPORTANT] The dry-run plugin does not skip the whole command. It only skips operations that command authors explicitly pass to run() or wrap(), so commands can still validate input, resolve configuration, and print useful context.

✨ Features

Global Dry-run Option

This plugin adds a global --dry-run option to all commands.

You can customize the option key with the name option. For example, name: 'pretend' maps to --pretend.

Explicit Side-effect Control

Dry-run behavior is opt-in per operation. Use:

  • run(): Run or skip a single side-effect task
  • wrap(): Wrap an existing function so every call respects dry-run mode

Fallback Results

For non-void operations, provide result or resolve so command code can continue in dry-run mode without executing the real side effect.

const releaseId = await dryRun.run(
  async function createRelease() {
    return await api.createRelease()
  },
  {
    result: 'dry-run-release',
    message: 'create release'
  }
)

Wrapping Existing Functions

wrap() is useful when you already have a side-effect function, such as a function from node:fs.

import { mkdir, writeFile } from 'node:fs/promises'

const writeOutputFile = dryRun.wrap(writeFile, {
  message: 'write output file'
})

await dryRun.run(
  async function createOutputDirectory() {
    await mkdir('dist', { recursive: true })
  },
  {
    message: 'create output directory'
  }
)

await writeOutputFile('dist/result.json', JSON.stringify({ ok: true }, null, 2))

⚙️ Plugin Options

name

  • Type: string
  • Default: 'dryRun'
  • Description: The command value key for the dry-run option. With Gunshi's default kebab-case option handling, dryRun maps to --dry-run.

description

  • Type: string
  • Default: 'Show what would be executed without running side effects'
  • Description: Fallback description for the dry-run global option.

descriptionResources

  • Type: Record<string, string>
  • Default: {}
  • Description: Localized global option descriptions used with @gunshi/plugin-i18n.

prefix

  • Type: string
  • Default: '[dryrun]'
  • Description: Prefix printed before dry-run messages.

🔗 Plugin Dependencies

The dry-run plugin has an optional dependency on the i18n plugin:

  • Plugin ID: g:i18n (optional)
  • Purpose: Provides localized descriptions for the dry-run global option
  • Effect: When the i18n plugin is present, the dry-run option description can be localized through descriptionResources

Example with i18n resources:

dryrun({
  description: 'Show what would be executed without running side effects',
  descriptionResources: {
    'ja-JP': '副作用のある処理を実行せず、実行予定の内容を表示する'
  }
})

🧩 Context Extensions

When using the dry-run plugin, your command context is extended via ctx.extensions['g:dryrun'].

[!IMPORTANT] This plugin extension is namespaced in CommandContext.extensions using this plugin ID g:dryrun by the gunshi plugin system.

Available extensions:

[!NOTE] The Awaitable<T> type used in the method signatures below is equivalent to T | Promise<T>, meaning the methods can return either a value directly or a Promise that resolves to that value.

  • enabled: boolean: Whether dry-run mode is enabled for the current command.

  • run<R>(task, options): Awaitable<R>: Run a side-effect task normally, or skip it and print a dry-run message when dry-run mode is enabled.

  • wrap<A, R>(fn, options): (...args: A) => Awaitable<R>: Wrap an existing side-effect function so calls are skipped and logged when dry-run mode is enabled.

Usage Example

import dryrun, { pluginId as dryrunId } from '@gunshi/plugin-dryrun'
import { cli, defineWithTypes } from 'gunshi'

import type { DryRunExtension } from '@gunshi/plugin-dryrun'

const command = defineWithTypes<{
  extensions: {
    [dryrunId]: DryRunExtension
  }
}>()({
  name: 'publish',
  async run(ctx) {
    const dryRun = ctx.extensions[dryrunId]

    if (dryRun.enabled) {
      console.log('Previewing publish steps')
    }

    await dryRun.run(
      async function publishPackage() {
        // Publish package here
      },
      {
        message: 'publish package'
      }
    )
  }
})

await cli(process.argv.slice(2), command, {
  plugins: [dryrun()]
})

📚 API References

See the API References

©️ License

MIT