An open API service indexing awesome lists of open source software.

https://github.com/nazmul-nhb/nhb-scripts

A collection of custom Node.js scripts to use in TypeScript & JavaScript projects
https://github.com/nazmul-nhb/nhb-scripts

cli ecma-script javascript nodejs script scripts typescript

Last synced: about 1 month ago
JSON representation

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

Awesome Lists containing this project

README

          

# NHB Scripts



Downloads


Latest Version



License

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](#-compatibility)
- [✅ Requirements](#-requirements)
- [⚙️ Unified Configuration System](#️-unified-configuration-system)
- [🧰 Included CLI Scripts](#-included-cli-scripts)
- [🔧 How to Use in Your Project](#-how-to-use-in-your-project)
- [🧱 nhb-module — Module Generator](#-nhb-module--module-generator)
- [⚙️ Setup in package.json](#️-setup-in-packagejson)
- [🛠️ What It Does](#️-what-it-does)
- [📦 Pre-built Template](#-pre-built-template)
- [📁 Custom Template Support](#-custom-template-support)
- [🧠 Why dynamic files?](#-why-dynamic-files)
- [🗂️ Template Files files](#️-template-files-files)
- [💡 CLI Flags](#-cli-flags)
- [🤖 What Happens Behind the Scenes](#-what-happens-behind-the-scenes)
- [📁 Output Example](#-output-example)
- [🧩 Template Shape](#-template-shape)
- [🔄 Lifecycle Hooks Optional](#-lifecycle-hooks-optional)
- [🛑 Cancel or Abort](#-cancel-or-abort)
- [🏗️ nhb-build — Customizable Build Runner with Progress Visualization](#️-nhb-build--customizable-build-runner-with-progress-visualization)
- [✨ Features](#-features)
- [⚙️ Configuration](#️-configuration)
- [🏗️ Options](#️-options)
- [📦 Usage](#-usage)
- [✅ Example Output](#-example-output)
- [🔧 Post‑Build Hooks](#-postbuild-hooks)
- [📝 nhb-commit — Commit Version Updates with Semver & Custom Message](#-nhb-commit--commit-version-updates-with-semver--custom-message)
- [⚙️ Setup in package.json](#️-setup-in-packagejson-1)
- [🚦 What It Does](#-what-it-does)
- [✨ Commit Format](#-commit-format)
- [🧩 Supported Types Predefined Choices](#-supported-types-predefined-choices)
- [💬 Prompt Flow](#-prompt-flow)
- [🧪 Semver Validations](#-semver-validations)
- [🔧 Behavior Summary](#-behavior-summary)
- [⚙️ Configuration](#️-configuration-1)
- [📌 Available Options](#-available-options)
- [✨ Formatter Integration Prettier](#-formatter-integration-prettier)
- [📁 Optional Formatter Config](#-optional-formatter-config)
- [📦 Combined Flow](#-combined-flow)
- [🛑 Cancel or Abort](#-cancel-or-abort-1)
- [🐕 nhb-husky - Setup Husky with Lint-Staged](#-nhb-husky---setup-husky-with-lint-staged)
- [📦 What It Does](#-what-it-does-1)
- [🎨 nhb-format — Code Formatter Prettier Runner](#-nhb-format--code-formatter-prettier-runner)
- [⚙️ Setup in package.json](#️-setup-in-packagejson-2)
- [📦 What It Does](#-what-it-does-2)
- [🛠️ Example Config](#️-example-config)
- [🔄 Automatic Integration with nhb-commit](#-automatic-integration-with-nhb-commit)
- [⚠️ Requirements](#️-requirements)
- [📁 Output Example](#-output-example-1)
- [✅ nhb-lint — ESLint Linter Runner](#-nhb-lint--eslint-linter-runner)
- [⚙️ Setup in package.json](#️-setup-in-packagejson-3)
- [✨ Features](#-features-1)
- [🛠️ Example Config](#️-example-config-1)
- [📦 Output Example](#-output-example-2)
- [🔧 nhb-fix — ESLint Auto‑Fix Runner](#-nhb-fix--eslint-autofix-runner)
- [⚙️ Setup in package.json](#️-setup-in-packagejson-4)
- [✨ Features](#-features-2)
- [📦 Output Example](#-output-example-3)
- [⚙️ Configuration](#️-configuration-2)
- [💡 Pro Tips](#-pro-tips)
- [📊 nhb-count — Export Counter CLI](#-nhb-count--export-counter-cli)
- [🔧 Usage](#-usage-1)
- [⚙️ Configuration](#️-configuration-3)
- [🧭 Interactive CLI Prompts](#-interactive-cli-prompts)
- [✅ Exactly What Happens](#-exactly-what-happens)
- [✅ Output Example](#-output-example-4)
- [📌 What It Detects](#-what-it-detects)
- [✅ Example](#-example)
- [🗑 nhb-delete – Interactive File & Folder Remover](#-nhb-delete--interactive-file--folder-remover)
- [🚀 Usage](#-usage-2)
- [✨ Features](#-features-3)
- [📌 Example](#-example-1)
- [📄 License](#-license)

## ⚡ Compatibility

Node.js 22+

> **Important:**
> `nhb-scripts` is designed **only for Node.js environments** (v22 or later).
> It is **not intended for browser environment**, so tools like [Bundlephobia](https://bundlephobia.com/) 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

```bash
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

All scripts use a single configuration file `nhb.scripts.config.mjs` that is automatically created if not present. Available configuration options include:


Details

```js
// @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](#-nhb-module--module-generator) | Scaffold module (folder with files) (e.g., Express + Mongoose + Zod by default) with templates. |
| [nhb-build](#️-nhb-build--customizable-build-runner-with-progress-visualization) | Customizable Build Runner with Progress Visualization. |
| [nhb-commit](#-nhb-commit--commit-version-updates-with-semver--custom-message) | Generate a conventional commit message interactively with validation. |
| [nhb-husky](#-nhb-husky---setup-husky-with-lint-staged) | Setup `husky` with `lint-staged` with `prettier` pre-commit hook. |
| [nhb-format](#-nhb-format--code-formatter-prettier-runner) | Format code with `prettier`. |
| [nhb-lint](#-nhb-lint--eslint-linter-runner) | Lint code with `eslint`. |
| [nhb-fix](#-nhb-fix--eslint-autofix-runner) | Fix linting errors in code with `eslint`. |
| [nhb-count](#-nhb-count--export-counter-cli) | Count export declarations (default, named, aliased) in JS/TS files/folders. |
| [nhb-delete](#-nhb-delete--interactive-file--folder-remover) | 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`:

```bash
yarn add -D nhb-scripts
```

```bash
pnpm add -D nhb-scripts
```

```bash
npm i -D nhb-scripts
```

Then in your `package.json`:

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

Now run any script like:

```bash
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:

```bash
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`

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

then use via:

```bash
pnpm module
```

```bash
yarn module
```

```bash
npm run module
```

or directly use as:

```bash
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`:

```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}` }
],
// 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**:

```js
files: [
{ name: 'index.ts', content: '// content' },
{ name: 'routes.ts', content: 'export const route = "auth";' },
]
```

2. **Dynamic function (recommended for reusable templates)**:

```js
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:

```bash
# 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:

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

Run:

```bash
pnpm module -n user -t basic-app
```

**Result:**

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

---

### 🧩 Template Shape

```ts
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`:

```js
// @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` | see below | Array of build commands. |
| `after` | `Array>` | `[]` | Hooks to run sequentially after build. |

**`BuildCommand` shape:**

```ts
{
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`:

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

then run via:

```bash
pnpm build
# or
npm run build
# or
yarn build
```

or directly use as:

```bash
pnpm nhb-build
```

---

### ✅ Example Output

```md
📦 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:

```js
// @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`

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

then run via:

```bash
pnpm commit
```

or directly use as:

```bash
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:

```bash
git add .
git commit -m "(): "
```

7. Ask for push permission (defaults to `Yes`).
8. Runs:

```bash
git push
```

---

### ✨ Commit Format

```bash
(optional-scope):
```

Examples:

```text
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

```bash
? 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`:

```js
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](#-nhb-format--code-formatter-prettier-runner) for details.

> If you prefer `husky` and `lint-staged` follow the [instructions here](#-nhb-husky---setup-husky-with-lint-staged).

---

### 📦 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:

```js
commit: {
runFormatter: false,
}
```

directly run:

```bash
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:

```json
{
"*.+((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](https://typicode.github.io/husky/) and [lint-staged](https://www.npmjs.com/package/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`

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

then run it via:

```bash
pnpm format
```

or directly use as:

```bash
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:

```js
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](#-nhb-commit--commit-version-updates-with-semver--custom-message) for more details.

---

### ⚠️ Requirements

Make sure `prettier` is installed in your `dependencies` or `devDependencies`:

```bash
pnpm add -D prettier
```

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

---

### 📁 Output Example

```bash
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`

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

then run via:

```bash
pnpm lint
# or
npm run lint
# or
yarn lint
```

or directly use as:

```bash
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`:

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

---

### 📦 Output Example

```bash
🚀 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`

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

then run via:

```bash
pnpm fix
# or
npm run fix
# or
yarn fix
```

or directly use as:

```bash
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

```bash
🚀 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`:

```js
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

```bash
pnpm count
```

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

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

then run via:

```bash
pnpm count
```

or directly use as:

```bash
pnpm nhb-count
```

---

### ⚙️ Configuration

In `nhb.scripts.config.mjs`:

```js
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:

```bash
📂 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

```bash
📦 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:

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

Output:

```bash
📦 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:

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

then run via:

```bash
pnpm delete
```

or directly use as:

```bash
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

```bash
🗑 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](LICENSE) © [Nazmul Hassan](mailto:nazmulnhb@gmail.com)