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

nhb-scripts

v1.9.2

Published

A collection of Node.js scripts to use in TypeScript & JavaScript projects

Readme

NHB Scripts

A developer-first toolkit to automate common dev tasks in JavaScript/TypeScript projects. Built to reduce repetitive boilerplate and improve developer velocity — no magic, just clean logic.

Table of Contents

⚡ Compatibility

Important:
nhb-scripts is designed only for Node.js environments (v22 or later).
It is not intended for browser environment, so tools like Bundlephobia may report missing browser dependencies.
This is expected behavior and does not affect usage in Node.js.

✅ Requirements

  • Node.js 22 or newer
  • npm, pnpm, or yarn for installation
pnpm add -D nhb-scripts
# or
npm install -D nhb-scripts
# or
yarn add -D nhb-scripts

⚙️ Unified Configuration System

Initialize configuration file by running the nhb-init command

// @ts-check

import { defineScriptConfig, expressMongooseZodTemplate } from 'nhb-scripts';

export default defineScriptConfig({
    format: {
        args: ['--write'],
        files: ['.'],
        ignorePath: '.prettierignore',
    },
    lint: { folders: ['src'], patterns: ['**/*.ts'] }, // Optional, these are defaults
    fix: { folders: ['src'], patterns: ['**/*.ts'] }, // Optional, these are defaults
    commit: {
        /** Run Prettier formatter before committing. Default is `false`. */
        runFormatter: true,
        /** Pre-hook to run before commit and after version change. */
        runBefore: () => {
          // Your logic here
        },
        /** Post-hook to run after commit and/or push. */
        runAfter: () => {
          // Your logic here
        },
        /** Wrap the prefix with custom symbols or any string, e.g. `"*"` makes the prefix looks like `"*type(scope):* your commit message"`. Default is empty string. */
        wrapPrefixWith: "`";
        /** Whether to prepend the corresponding emoji before the commit type prefix (applied only for the default ones). Default is `false`. */
        emojiBeforePrefix: true, // Omit `emojiBeforePrefix` to use default `false`.
        /** Options for extending commit types */
        commitTypes: {
          /** Whether to override the default commit types. Defaults to `false` */
          overrideDefaults?: false,
          /** Array of custom commit types with emoji and type names */
          custom: [
            { emoji: '🏃‍♂️‍➡️', type: 'run' },
            // more custom types
          ]
        },
    },
    count: {
        defaultPath: '.', // default path to scan
        excludePaths: ['node_modules', 'dist', 'build'] // folders to exclude
    },
    build: {
      distFolder: 'dist', // optional, default: "dist"
      deleteDist: true, // delete dist folder before each build, set `false` to keep dist folder intact
      showOutputs: true, // display output file list, default is `false`
      waitingMessage: ' 📦 Building Your Server...', // Message to display while build process is running
      commands: [ // default is [{cmd: 'tsc'}]
          // Not default
          { cmd: 'tsc', args: ['-p', 'tsconfig.cjs.json'] },
          // Not default
          {
              cmd: 'tsc',
              args: ['-p', 'tsconfig.esm.json'],
              options: { stdio: 'inherit' }
          }
      ],
      after: [
          // Not default
          async () => await fixJsExtensions('dist/esm'),
          // Not default
          async () => await fixTypeExports({
              distPath: 'dist/dts',
              packageJsonPath: 'package.json',
              typeFileCandidates: ['types.d.ts', 'interfaces.d.ts'],
              extraPatterns: [
                  { pattern: 'plugins', folderName: 'plugins' },
              ],
              extraStatic: {
                  './types': {
                      types: './dist/dts/types/index.d.ts',
                      default: './dist/dts/types/index.d.ts'
                  },
                  './constants': {
                      types: './dist/dts/constants.d.ts',
                      import: './dist/esm/constants.js',
                      require: './dist/cjs/constants.js'
                  },
              }
          }),
      ],
    },
    module: {
        destination: 'src/modules', // optional, default: "src/modules"
        defaultTemplate: 'my.template1', // selected by default, must match with the keys of `templates` object
        force: false, // `true` if you want to override the existing module
        templates: {
            'express-mongoose-zod': {
                createFolder: true,
                destination: 'src/app/modules',
                files: expressMongooseZodTemplate // pre-built module : function that receives moduleName as argument and creates pre-defined files and contents
            },
            'my.template1': {
                createFolder: true, // if `false` does not create folder with the module name from cli
                destination: 'src/app', // optional, will prioritize inputs from cli
                // Use dynamic moduleName in filenames and contents
                files: (moduleName) => [
                    { name: `${moduleName}.controllers.ts`, content: `// controllers for ${moduleName}` },
                    { name: `${moduleName}.services.ts`, content: `// services for ${moduleName}` }
                ]
            },
            'my_template2': {
                destination: 'src/features', // optional, will prioritize inputs from cli
                // Use static file list with contents
                files: [
                    { name: 'index.ts', content: '// content' },
                    { name: 'dummy.js', content: '// dummy' }
                ]
            },
        },
        // Optional hooks to inspect or execute something at the beginning or after the module generation
        hooks: {
            onGenerate(name) {
                console.log('➡️  Generating:', name);
            },
            onComplete(name) {
                console.log('✅ Complete:', name);
            }
        }
    }
});

🧰 Included CLI Scripts

| Script | Description | | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | nhb-init | Initialize the config file. | | nhb-module | Scaffold module (folder with files) (e.g., Express + Mongoose + Zod by default) with templates. | | nhb-build | Customizable Build Runner with Progress Visualization. | | nhb-commit | Generate a conventional commit message interactively with validation. | | nhb-husky | Setup husky with lint-staged with prettier pre-commit hook. | | nhb-format | Format code with prettier. | | nhb-lint | Lint code with eslint. | | nhb-fix | Fix linting errors in code with eslint. | | nhb-count | Count export declarations (default, named, aliased) in JS/TS files/folders. | | nhb-delete | Interactive File(s)/Folder(s) Remover. |

Most of the examples here are shown using pnpm as package manager, you can use other package managers like npm or yarn or others.


🔧 How to Use in Your Project

Add to your devDependencies:

yarn add -D nhb-scripts
pnpm add -D nhb-scripts
npm i -D nhb-scripts

Then in your package.json:

{
  "scripts": {
    "module": "nhb-module",
    "commit": "nhb-commit",
    "format": "nhb-format",
    "count": "nhb-count"
  }
}

Now run any script like:

pnpm module      # 🧩 Generate a new module
pnpm commit      # ✅ Bump version & commit changes
pnpm format      # 🎨 Format code with prettier
pnpm count       # 📦 Count exports in files

Or without package.json setup:

pnpm nhb-module      # 🧩 Generate a new module
pnpm nhb-commit      # ✅ Bump version & commit changes
pnpm nhb-format      # 🎨 Format code with prettier
pnpm nhb-count       # 📦 Count exports in files

Replace pnpm with npm run or yarn if you're using those instead.


🧱 nhb-module — Module Generator

Scaffold consistent, production-ready API modules in your codebase using prebuilt or custom-defined templates.

This CLI simplifies creating module directories and boilerplate files with optional configuration, hooks, and folder override logic.


⚙️ Setup in package.json

{
  "scripts": {
    "module": "nhb-module"
  }
}

then use via:

pnpm module
yarn module
npm run module

or directly use as:

pnpm nhb-module

🛠️ What It Does

  • Prompts for module name, destination, and template (unless passed as CLI flags).
  • Uses a pre-built template (express-mongoose-zod : imported function expressMongooseZodTemplate) or your custom templates via a config file.
  • Prevents overwriting by default unless --force is passed or set in config.
  • Allows lifecycle hooks: onGenerate, onComplete.

📦 Pre-built Template

| Name | Description | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------- | | express-mongoose-zod | Basic Express route + Mongoose model + Zod schema generator (built-in : imported function expressMongooseZodTemplate) |


📁 Custom Template Support

Configure templates in nhb.scripts.config.mjs:

module: {
    destination: 'src/modules', // optional, default: "src/modules"
    defaultTemplate: 'my.template1', // selected by default, must match with the keys of `templates` object
    force: false, // `true` if you want to override the existing module
    templates: {
        'express-mongoose-zod': {
            createFolder: true,
            destination: 'src/app/modules',
            files: expressMongooseZodTemplate // pre-built module : function that receives moduleName as argument and creates pre-defined files and contents
        },
        'my.template1': {
            createFolder: true, // if `false` does not create folder with the module name from cli
            destination: 'src/app', // optional, will prioritize inputs from cli
            // Use dynamic moduleName in filenames and contents
            files: (moduleName) => [
                { name: `${moduleName}.controllers.ts`, content: `// controllers for ${moduleName}` },
                { name: `${moduleName}.services.ts`, content: `// services for ${moduleName}` }
            ],
            // Runs before this specific module generation (Optional)
            onGenerate(name) {
                Stylog.ansi16('yellow').bold.log(`${name} Started!`);
            },
            // Runs after this specific module generation (Optional)
            onComplete(name) {
                Stylog.ansi16('green').bold.log(`${name} Completed!`);
            },
        },
        'my_template2': {
            destination: 'src/features', // optional, will prioritize inputs from cli
            // Use static file list with contents
            files: [
                { name: 'index.ts', content: '// content' },
                { name: 'dummy.js', content: '// dummy' }
            ]
        },
    },
    // Optional hooks to inspect or execute something at the beginning or after the module generation (runs for all templates)
    hooks: {
        onGenerate(name) {
            console.log('➡️  Generating:', name);
        },
        onComplete(name) {
            console.log('✅ Complete:', name);
        }
    }
}

🧠 Why dynamic files()?

If your filenames or content need to reference the module name (e.g. auth.controller.ts), use the function form. It provides full flexibility for templates that depend on runtime values.

🗂️ Template Files (files)

You can provide either of the following:

  1. Static array of file entries:

    files: [
      { name: 'index.ts', content: '// content' },
      { name: 'routes.ts', content: 'export const route = "auth";' },
    ]
  2. Dynamic function (recommended for reusable templates):

    files: (moduleName) => [
      { name: `${moduleName}.controller.ts`, content: `// controller for ${moduleName}` },
      { name: `${moduleName}.service.ts`, content: `// service for ${moduleName}` },
    ]

💡 Note: You can and should write actual code inside the content field using template strings — works with any language! 💡 File names (name) can include folders like { name: 'utils/helper.ts' }. Folders will be auto-created if missing.


💡 CLI Flags

You can also generate modules non-interactively using CLI flags to streamline automation or scripting:

| Flag | Alias | Description | | ----------------- | ----- | -------------------------------------------- | | --name | -n | Name of the module | | --template | -t | Template to use | | --destination | -d | Directory to generate module into | | --force | -f | Overwrite existing module if already present | | --create-folder | -cf | Create folder for module (default: true) |

Example:

# Using full flags
pnpm module --name=user --template=basic-app --destination=src/features --force

# Using full flags but without equal sign
pnpm module --name user --template basic-app --destination src/features --force

# Using aliases
pnpm module -n auth -t express-mongoose-zod -d src/modules

# Force overwrite if module exists
pnpm module -n blog -t express-mongoose-zod -d src/modules -f

# With create folder flag
pnpm module --name=user --template=basic-app --destination=src/features --force --create-folder=false

# Using aliases
pnpm module -n auth -t express-mongoose-zod -d src/modules -cf false

🤖 What Happens Behind the Scenes

  1. 🔍 Looks for a config file (offers to create one if missing).
  2. 🧱 Asks for module name, template, and destination (or use flags).
  3. ⚙️ Merges CLI flags with config values.
  4. 🚧 Warns if module exists — prompts overwrite unless --force.
  5. 🏗️ Generates module files from the selected template.
  6. 🔁 Runs onGenerate and onComplete hooks if configured.

📁 Output Example

Given:

module: {
    destination: 'src/features',
    customTemplates: {
        'basic-app': {
            files: (name) => [
                { name: `${name}.ts`, content: `// module: ${name}` },
                { name: `${name}.routes.ts`, content: `// routes for ${name}` }
            ]
        }
    }
}

Run:

pnpm module -n user -t basic-app

Result:

src/features/user/
├── user.ts           → // module: user
└── user.routes.ts    → // routes for user

🧩 Template Shape

type FileEntry = {
  name: string;       // file path relative to the module dir
  content: string;    // file contents
};

type CustomTemplate = {
  destination?: string;
  files: FileEntry[] | ((moduleName: string) => FileEntry[]);
};

You can define multiple templates and dynamically select one at CLI prompt or via --template.


🔄 Lifecycle Hooks (Optional)

| Hook | Signature | Purpose | | ------------ | ------------------------------ | --------------------------- | | onGenerate | (moduleName: string) => void | Before writing module files | | onComplete | (moduleName: string) => void | After writing module files |


🛑 Cancel or Abort

  • If a module already exists and --force is not used, the CLI prompts confirmation.
  • You can abort at any step via keyboard interrupt (Ctrl+C or Esc on prompts).

🏗️ nhb-build — Customizable Build Runner with Progress Visualization

A configurable build runner with progress estimator that can execute your build commands in sequence (e.g., tsc, rollup, vite) and then run optional post‑build hooks like fixTypeExports() or fixJsExtensions().

✨ Features

  • ✅ Define any build commands in your nhb.scripts.config.mjs (defaults to tsc).
  • ✅ Dynamically add multiple commands with arguments and execa options.
  • ✅ Always cleans your specified dist folder (using rimraf) before each build to avoid conflicts. You can configure this behavior.
  • ✅ Run post‑build hooks (after) as an array of async functions (e.g., fixJsExtensions('dist/esm')).
  • ✅ Rich output: shows file sizes, count, and total build time.
  • ✅ Optionally shows output file list. Set showOutputs: true in the config to display the list of output files.

⚙️ Configuration

Add a build section in your nhb.scripts.config.mjs:

// @ts-check
import { defineScriptConfig, fixJsExtensions, fixTypeExports} from 'nhb-scripts';

export default defineScriptConfig({
  // Other configs...
  build: {
    distFolder: 'output', // optional, default: "dist"
    deleteDist: true, // delete dist folder before each build, set `false` to keep dist folder intact
    showOutputs: true, // display output file list, default is `false`
    waitingMessage: ' 📦 Building Your Server...', // Message to display while build process is running
    commands: [
      { cmd: 'tsc', args: ['-p', 'tsconfig.cjs.json'] },
      { cmd: 'tsc', args: ['-p', 'tsconfig.esm.json'], options: { stdio: 'inherit' } }
    ],
    after: [
        async () => await fixJsExtensions('dist/esm'),
        async () => await fixTypeExports({
            distPath: 'dist/dts',
            packageJsonPath: 'package.json',
            typeFileCandidates: ['types.d.ts', 'interfaces.d.ts'],
            extraPatterns: [
                { pattern: 'plugins', folderName: 'plugins' },
            ],
            extraStatic: {
                './types': {
                    types: './dist/dts/types/index.d.ts',
                    default: './dist/dts/types/index.d.ts'
                },
                './constants': {
                    types: './dist/dts/constants.d.ts',
                    import: './dist/esm/constants.js',
                    require: './dist/cjs/constants.js'
                },
            }
        }),
    ],
  }
});

🏗️ Options

| Field | Type | Default | Description | | ---------------- | ---------------------- | ------------------------------------- | ----------------------------------------------- | | distFolder | string | dist | Output folder used for size reporting. | | deleteDist | boolean | true | Whether to delete old output before each build. | | showOutputs | boolean | false | Whether to display the list of output files. | | waitingMessage | string | ' 📦 Building Your Application...' | Message to display while building. | | commands | Array<BuildCommand> | see below | Array of build commands. | | after | Array<Promise<void>> | [] | Hooks to run sequentially after build. |

BuildCommand shape:

{
  cmd: string;           // executable to run (e.g. "tsc", "rimraf")
  args?: string[];       // arguments for the command
  options?: import('execa').Options; // additional execa options
}

📦 Usage

Add to package.json:

{
  "scripts": {
    "build": "nhb-build"
  }
}

then run via:

pnpm build
# or
npm run build
# or
yarn build

or directly use as:

pnpm nhb-build

✅ Example Output

📦 Build Your Application
─────────────────────────────────────────────
Building Your Application...

✓ Transformed Files:
🟨 dist/esm/index.js                              3.20 kB
🟦 dist/dts/index.d.ts                            0.45 kB
🟩 dist/esm/index.js.map                          1.15 kB
...
✓ Total Files: 25; Total Size: 89.42 kB
📦 Application was built in 3.27 seconds!

🔧 Post‑Build Hooks

after hooks run after all build commands succeed, in order. You can pass any async function returning a Promise, for example:

// @ts-check

import { fixJsExtensions, fixTypeExports} from 'nhb-scripts';

export default defineScriptConfig({
  build: {
    after: [
        async () => await fixJsExtensions('dist/esm'),
        async () => await fixTypeExports({
            distPath: 'dist/dts',
            packageJsonPath: 'package.json',
            typeFileCandidates: ['types.d.ts', 'interfaces.d.ts'],
            extraPatterns: [
                { pattern: 'plugins', folderName: 'plugins' },
            ],
            extraStatic: {
                './types': {
                    types: './dist/dts/types/index.d.ts',
                    default: './dist/dts/types/index.d.ts'
                },
                './constants': {
                    types: './dist/dts/constants.d.ts',
                    import: './dist/esm/constants.js',
                    require: './dist/cjs/constants.js'
                },
            }
        }),
    ],
  }
});

Tip: Because nhb-build uses execa, all commands respect your local environment and cwd, so you can run any build tools your project needs.


📝 nhb-commit — Commit Version Updates with Semver & Custom Message

A simple, interactive CLI to:

  • Safely bump the package version (package.json)
  • Add a conventional typed Git commit message (with optional scope)
  • Automatically commit and push (will ask for permission to push to the remote repository)

This ensures your version bumps and commit messages are semver-valid, consistent, and expressive.


⚙️ Setup in package.json

{
  "scripts": {
    "commit": "nhb-commit"
  }
}

then run via:

pnpm commit

or directly use as:

pnpm nhb-commit

🚦 What It Does

  1. Prompts for new version (or skip to use the current).

  2. Prompts for a commit type (e.g., feat, fix, refactor, etc.).

  3. Prompts optionally for a scope (e.g., auth, ui, etc.).

  4. Requires a commit message.

  5. Updates package.json version.

  6. Runs:

    git add .
    git commit -m "<type>(<scope>): <message>"
  7. Ask for push permission (defaults to Yes).

  8. Runs:

    git push

✨ Commit Format

<type>(optional-scope): <message>

Examples:

feat(api): add user registration flow
fix: resolve async deadlock issue
refactor(db): improve mongoose connection handling

🧩 Supported Types (Predefined Choices)

Default type: update

| Type | Description | | ---------- | ------------------------------------ | | update | 🔧 General update (default) | | feat | ✨ New feature | | fix | 🐛 Bug fix | | chore | 🛠️ Maintenance task (e.g., deps) | | refactor | 🧼 Internal logic change | | test | 🧪 Adding/fixing tests | | docs | 📚 Documentation-only change | | style | 💅 Code formatting, styling etc. | | perf | ⚡ Performance improvement | | ci | 🚀 CI-related changes | | build | 🧱 Build system changes | | revert | 🔁 Revert a previous commit | | release | 🔖 Version bump or release | | deps | 📦 Dependency updates | | cleanup | 🧹 Minor cleanup tasks | | merge | 🧭 Merge-related commits | | Custom | ✍️ Manually enter your own |


💬 Prompt Flow

? Current version: 1.3.4
? Enter new version (or press Enter to keep): 1.4.0
? Select commit type: Predefined type or a custom one
? Enter custom commit type: update/fix etc. or infra (whatever custom type you want)
? Enter commit scope (optional): devops
? Enter commit message (required): configure docker build

✔ Commit message → infra(devops): configure docker build
✔ Version updated to 1.4.0
✔ Committed successfully 
? Ask for push permission (defaults to 'Yes')!
✔ Pushed successfully!

🧪 Semver Validations

  • Prevents invalid semver input
  • Ensures new version is equal to or greater than current
  • Allows skipping version bump by pressing Enter

🔧 Behavior Summary

Note: Git must be installed, and your repository must be initialized with a remote named origin. This is required because the script automatically commits and pushes version changes to your Git remote.

| Step | Behavior | | ---------------- | ----------------------------------------------------------------------- | | version prompt | Accepts semver (e.g., 1.2.3, 2.0.0-beta.1) or press Enter to skip | | type prompt | Choose from predefined types or default (update) | | scope prompt | Optional. If blank, excluded from final commit message | | message prompt | Required. Validates non-empty | | git operations | Adds all changes, commits, pushes with composed message |

You can also override or extend the default types + emojis from the configuration option commitTypes.


⚙️ Configuration

In nhb.scripts.config.mjs:

commit: {
    runFormatter: false, // Set `true` to run Prettier before committing
    /** Wrap the prefix with custom symbols or any string, e.g. "*" makes the prefix looks like "*type(scope):* your commit message". Default is empty string. */
    wrapPrefixWith: "`";
    /** Whether to prepend the corresponding emoji before the commit type prefix (applied only for the default ones). Default is `false`. */
    emojiBeforePrefix: true, // Omit `emojiBeforePrefix` to use default `false`.
    /** Pre-hook to run before commit and after version change. */
    runBefore: () => {
      console.log('Pre-hook is called...')
    },
    /** Post-hook to run after commit and/or push. */
    runAfter: () => {
      console.log('Post-hook is called...')
    },
    /** Options for extending commit types */
    commitTypes: {
      /** Whether to override the default commit types. Defaults to `false` */
      overrideDefaults?: false,
      /** Array of custom commit types with emoji and type names */
      custom: [
        { emoji: '🏃‍♂️‍➡️', type: 'run' },
        // more custom types
      ]
    }
}

📌 Available Options

| Option | Type | Default | Description | | ------------------- | -------- | ----------- | ----------------------------------------------------------------------------- | | runFormatter | boolean | false | Whether to automatically run Prettier before committing. | | runBefore | Function | undefined | Whether to automatically run pre-hook before committing. | | runAfter | Function | undefined | Whether to automatically run post-hook after committing. | | wrapPrefixWith | string | "" | Wrap the prefix with custom symbols or any string. | | emojiBeforePrefix | boolean | false | Whether to prepend the corresponding emoji before the commit type prefix. |


✨ Formatter Integration (Prettier)

If runFormatter: true is enabled in the config:

  • It ensures .prettierrc.json and .prettierignore exist.
  • It runs prettier --write . or customized options from nhb.format.config.mjs (if present) before staging changes.

💡 This ensures your code is always formatted before being committed!


📁 Optional Formatter Config

You can also define a custom formatter config.

Please refer to nhb-format for details.

If you prefer husky and lint-staged follow the instructions here.


📦 Combined Flow

If both configs are present and runFormatter is true, nhb-commit will:

  1. Load your nhb.format.config.mjs (if available).
  2. Run Prettier formatting.
  3. Proceed to version update and Git commit.

🛑 Cancel or Abort

You can abort at any time using Ctrl+C or Esc.


🐕 nhb-husky - Setup Husky with Lint-Staged

Setup husky with lint-staged with prettier pre-commit hook quickly.

If you use husky with lint-staged make sure to set runFormatter: false in nhb.scripts.config.mjs file:

commit: {
    runFormatter: false,
}

directly run:

pnpm nhb-husky

📦 What It Does

  1. Installs husky and lint-staged if not installed already.

  2. Configures .husky/pre-commit file with proper lint-staged setup.

  3. Creates .lintstagedrc.json file with following config:

    {
      "*.+((c|m)?js(x)?|(c|m)?ts(x)?)": [
        "prettier --write"
      ]
    }

    If .lintstagedrc.json file already exists, it skips creating this file.

For further configuration for these files, please refer to their official docs: husky and lint-staged


🎨 nhb-format — Code Formatter (Prettier Runner)

A script that ensures clean and consistent formatting using Prettier, with optional config and auto-scaffolding support.


⚙️ Setup in package.json

{
  "scripts": {
    "format": "nhb-format"
  }
}

then run it via:

pnpm format

or directly use as:

pnpm nhb-format

📦 What It Does

  1. Ensures .prettierrc.json and .prettierignore exist in the project root (auto-generates if missing).

  2. Loads user config from:

    • nhb.scripts.config.mjs or
    • nhb.scripts.config.js
  3. Executes Prettier with the defined args/files.

💡 If no config file exists, it runs Prettier with default args: --write .


🛠️ Example Config

Update format1 property in nhb.scripts.config.mjs file:

format: {
    args: ['--write'],
    files: ['src', 'lib'],
    ignorePath: '.prettierignore'
}

🔄 Automatic Integration with nhb-commit

If runFormatter: true is set in your nhb.commit.config.mjs, the formatter will be triggered before committing. See nhb-commit for more details.


⚠️ Requirements

Make sure prettier is installed in your dependencies or devDependencies:

pnpm add -D prettier

If missing, the script will exit with a warning and suggest installation.


📁 Output Example

pnpm format

🎨 Running Prettier...

# Scanned file-list

✅ Prettier formatting complete!

nhb-lint — ESLint Linter Runner

Run ESLint across your project with a unified configuration system. It automatically detects your folders and patterns from nhb.scripts.config.mjs and shows a detailed lint summary with all issues.

⚙️ Setup in package.json

{
  "scripts": {
    "lint": "nhb-lint"
  }
}

then run via:

pnpm lint
# or
npm run lint
# or
yarn lint

or directly use as:

pnpm nhb-lint

✨ Features

  • ✅ Auto‑detects and ensures ESLint configuration (.eslintrc.cjs etc.)
  • ✅ Loads lint config (folders, patterns) from nhb.scripts.config.mjs
  • ✅ Rich output with a bullet‑point summary of all ESLint findings
  • ✅ Shows scanned file count and total runtime
  • ✅ Works with TypeScript & JavaScript projects (ESM only)

🛠️ Example Config

In nhb.scripts.config.mjs:

lint: {
  folders: ['src', 'tests'],        // optional; default: ["src"]
  patterns: ['**/*.ts', '**/*.tsx'] // optional; default: ["**/*.ts"]
}

📦 Output Example

🚀 Run ESLint Linter
⏳ Linting Your Code in src, tests...

✓ Lint Summary
 • src/index.ts:12:3  warning  Unexpected console statement  no-console
 • src/utils/helpers.ts:45:10  error  Missing return type on function  @typescript-eslint/explicit-module-boundary-types
 • tests/app.spec.ts:5:1  error  Prefer const over let  prefer-const

✓ Scanned total 58 files in 2.43 seconds!
🎉 Linting completed in folders: src, tests

🔧 nhb-fix — ESLint Auto‑Fix Runner

Run ESLint with the --fix flag to automatically fix many common issues in your code.

⚙️ Setup in package.json

{
  "scripts": {
    "fix": "nhb-fix"
  }
}

then run via:

pnpm fix
# or
npm run fix
# or
yarn fix

or directly use as:

pnpm nhb-fix

✨ Features

  • ✅ Same detection and configuration as nhb-lint
  • ✅ Applies auto‑fixable rules (formatting, unused vars, etc.)
  • ✅ Shows a fix summary with all changes applied
  • ✅ Counts scanned files and shows runtime

📦 Output Example

🚀 Run ESLint Linter
⏳ Fixing Your Code in src...

✓ Fix Summary
 • src/utils/array.ts:12:1  fixed  Remove unused import
 • src/components/Button.tsx:5:1  fixed  Format JSX spacing

✓ Scanned total 58 files in 2.02 seconds!
🎉 Fixing completed in folders: src

⚙️ Configuration

nhb-fix use the fix section in nhb.scripts.config.mjs:

fix: {
  folders: ['src'],        // Folders to lint
  patterns: ['**/*.ts']    // Glob patterns per folder
}

💡 Pro Tips

  • Run pnpm lint before pushing to catch errors early.
  • Run pnpm fix to automatically resolve fixable issues.
  • Combine with nhb-commit (runFormatter option) for a fully automated commit pipeline.

📊 nhb-count — Export Counter CLI

Analyze the structure of JavaScript/TypeScript modules to detect and count:

  • Default exports
  • Named exports
  • Aliased named exports
  • Type-only named exports (export type { ... })

⚠ Only supports files that use ES-style exports (export, export default). CommonJS-style (module.exports, exports.foo) is not currently counted.


🔧 Usage

pnpm count

Note: This must be configured in your package.json scripts:

{
  "scripts": {
    "count": "nhb-count"
  }
}

then run via:

pnpm count

or directly use as:

pnpm nhb-count

⚙️ Configuration

In nhb.scripts.config.mjs:

count: {
    defaultPath: '.', // Default path when no input is provided
    excludePaths: [   // Directories automatically excluded
        'node_modules',
        'dist', 
        'build'
    ]
}

🧭 Interactive CLI Prompts

When executed, the script will prompt you:

📂 Export Counter
───────────────────────────────────────────────────────────────────────────────-----
🎯 Please specify the path to a "js/ts/mjs" file or folder containing "js/ts/mjs" files.
   - Enter file path (with extension) to analyze one file
   - Enter folder path to scan recursively
   - Press Enter to use default path: [shows configured defaultPath]

✅ Exactly What Happens

  1. If you enter a file path:

    • Must be .js, .ts, or .mjs
    • Analyzes only that file
  2. If you enter a folder path:

    • Recursively scans for matching files
    • Automatically excludes node_modules, dist, build
    • Respects additional excludePaths from config
  3. If you press Enter:

    • Uses defaultPath from config (defaults to .)

✅ Output Example

📦 Export Summary for "src/utils/math.ts":
🔸 Default Exports         : 1
🔹 Named Exports (Total)   : 5
   ┣ Direct                : 3
   ┗ Aliased               : 2 
🔺 Total Type Exports      : 4

Key Notes:

  • No command-line arguments accepted
  • Path must be entered interactively
  • Default path comes from config
  • Exclusion rules are automatic

📌 What It Detects

| Count Type | Description | | --------------------- | ------------------------------------------------------------------ | | default | Number of export default statements | | namedExportsTotal | Total export { x, y as z } style exports, including aliased ones | | namedExportsDirect | Named exports without aliases (e.g., export { foo }) | | namedExportsAliased | Named exports using as keyword (e.g., export { foo as bar }) | | namedTypeExports | Type-only exports (e.g., export type { MyType }) |


✅ Example

Given this file:

export default function main() {}
export const foo = 42;
export { bar as renamedBar };
export type { SomeType };

Output:

📦 Export Summary for "some/file.ts":
🔸 Default Exports        : 1
🔹 Named Exports (Total)  : 2
   ┣ Direct               : 1
   ┗ Aliased              : 1
🔺 Total Type Exports     : 1

🗑 nhb-delete – Interactive File & Folder Remover

Safely clean up your project with a guided, prompt‑driven experience to browse and delete files or directories.

Deleting large or deeply nested folders from VS Code often takes a long time or fails unexpectedly — nhb-delete offers a faster and more reliable solution.

✅ Navigate into sub-folders or go back anytime
✅ Multi‑select files and folders for deletion
✅ Empty folders immediately prompt for deletion
✅ Skips opening truly empty directories

🚀 Usage

Note: This must be configured in your package.json scripts:

{
  "scripts": {
    "delete": "nhb-delete"
  }
}

then run via:

pnpm delete

or directly use as:

pnpm nhb-delete

✨ Features

  • Interactive navigation: step through your folders with clear prompts.
  • Smart listings: if only files exist, jump straight to multi‑select.
  • Empty folder handling: offers deletion instead of opening.
  • Safe confirmation: always double‑checks before removal.

📌 Example

🗑 Delete Directory/File(s)
? Enter a base path or choose current directory ›
❯ 📂 Current Directory
  ✏️  Enter manually

Use Space to select and Enter to confirm — perfect for cleaning up scaffolds, build artifacts, or leftover files.


Built with ❤️ to make developer lives easier – because every second saved is a second earned.

📄 License

MIT © Nazmul Hassan