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.
- ⚡ Compatibility
- ⚙️ Unified Configuration System
- 🧰 Included CLI Scripts
- 🔧 How to Use in Your Project
- 🧱 nhb-module — Module Generator
- 🏗️ nhb-build — Customizable Build Runner with Progress Visualization
- 📝 nhb-commit — Commit Version Updates with Semver & Custom Message
- 🐕 nhb-husky - Setup Husky with Lint-Staged
- 🎨 nhb-format — Code Formatter Prettier Runner
- ✅ nhb-lint — ESLint Linter Runner
- 🔧 nhb-fix — ESLint Auto‑Fix Runner
- 📊 nhb-count — Export Counter CLI
- 📄 License
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 inNode.js
.
- Node.js 22 or newer
npm
,pnpm
, oryarn
for installation
pnpm add -D nhb-scripts
# or
npm install -D nhb-scripts
# or
yarn add -D nhb-scripts
All scripts use a single configuration file nhb.scripts.config.mjs
that is automatically created if not present. Available configuration options include:
// @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`.
},
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`
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);
}
}
}
});
Script | Description |
---|---|
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. |
More Scripts Coming Soon...
Most of the examples here are shown using
pnpm
as package manager, you can use other package managers likenpm
oryarn
or others.
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
withnpm run
oryarn
if you're using those instead.
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.
{
"scripts": {
"module": "nhb-module"
}
}
then use via:
pnpm module
yarn module
npm run module
or directly use as:
pnpm nhb-module
- Prompts for module name, destination, and template (unless passed as CLI flags).
- Uses a pre-built template (
express-mongoose-zod
: imported functionexpressMongooseZodTemplate
) 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
.
Name | Description |
---|---|
express-mongoose-zod |
Basic Express route + Mongoose model + Zod schema generator (built-in : imported function expressMongooseZodTemplate ) |
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);
}
}
}
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.
You can provide either of the following:
-
Static array of file entries:
files: [ { name: 'index.ts', content: '// content' }, { name: 'routes.ts', content: 'export const route = "auth";' }, ]
-
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.
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
- 🔍 Looks for a config file (offers to create one if missing).
- 🧱 Asks for module name, template, and destination (or use flags).
- ⚙️ Merges CLI flags with config values.
- 🚧 Warns if module exists — prompts overwrite unless
--force
. - 🏗️ Generates module files from the selected template.
- 🔁 Runs
onGenerate
andonComplete
hooks if configured.
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
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
.
Hook | Signature | Purpose |
---|---|---|
onGenerate |
(moduleName: string) => void |
Before writing module files |
onComplete |
(moduleName: string) => void |
After writing module files |
- 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
orEsc
on prompts).
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()
.
- ✅ Define any build commands in your
nhb.scripts.config.mjs
(defaults totsc
). - ✅ 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.
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`
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'
},
}
}),
],
}
});
Field | Type | Default | Description |
---|---|---|---|
distFolder |
string |
dist |
Output folder used for size reporting and cleanup. |
deleteDist |
boolean |
true |
Whether to delete the dist (output) folder before each build. |
showOutputs |
boolean |
false |
Whether to display the list of output files. |
commands |
Array<BuildCommand> |
see below | Array of build commands. |
after |
Array<Promise<void>> |
[] |
Post‑build hooks to run sequentially after commands finish. |
BuildCommand
shape:
{
cmd: string; // executable to run (e.g. "tsc", "rimraf")
args?: string[]; // arguments for the command
options?: import('execa').Options; // additional execa options
}
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
📦 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!
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
usesexeca
, all commands respect your local environment andcwd
, so you can run any build tools your project needs.
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.
{
"scripts": {
"commit": "nhb-commit"
}
}
then run via:
pnpm commit
or directly use as:
pnpm nhb-commit
-
Prompts for new version (or skip to use the current).
-
Prompts for a commit type (e.g.,
feat
,fix
,refactor
, etc.). -
Prompts optionally for a scope (e.g.,
auth
,ui
, etc.). -
Requires a commit message.
-
Updates
package.json
version. -
Runs:
git add . git commit -m "<type>(<scope>): <message>"
-
Ask for push permission (defaults to
Yes
). -
Runs:
git push
<type>(optional-scope): <message>
Examples:
feat(api): add user registration flow
fix: resolve async deadlock issue
refactor(db): improve mongoose connection handling
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 |
? 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!
- Prevents invalid semver input
- Ensures new version is equal to or greater than current
- Allows skipping version bump by pressing
Enter
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 |
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...')
},
}
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. |
If runFormatter: true
is enabled in the config:
- It ensures
.prettierrc.json
and.prettierignore
exist. - It runs
prettier --write .
or customized options fromnhb.format.config.mjs
(if present) before staging changes.
💡 This ensures your code is always formatted before being committed!
You can also define a custom formatter config.
Please refer to nhb-format for details.
If you prefer
husky
andlint-staged
follow the instructions here.
If both configs are present and runFormatter
is true
, nhb-commit
will:
- Load your
nhb.format.config.mjs
(if available). - Run Prettier formatting.
- Proceed to version update and Git commit.
You can abort at any time using Ctrl+C
or Esc
.
Setup husky
with lint-staged
with prettier
pre-commit hook quickly.
If you use husky with lint-staged make sure to set
runFormatter: false
innhb.scripts.config.mjs
file:
commit: {
runFormatter: false,
}
directly run:
pnpm nhb-husky
-
Installs
husky
andlint-staged
if not installed already. -
Configures
.husky/pre-commit
file with properlint-staged
setup. -
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
A script that ensures clean and consistent formatting using Prettier, with optional config and auto-scaffolding support.
{
"scripts": {
"format": "nhb-format"
}
}
then run it via:
pnpm format
or directly use as:
pnpm nhb-format
-
Ensures
.prettierrc.json
and.prettierignore
exist in the project root (auto-generates if missing). -
Loads user config from:
nhb.scripts.config.mjs
ornhb.scripts.config.js
-
Executes Prettier with the defined args/files.
💡 If no config file exists, it runs Prettier with default args:
--write .
Update format1 property in nhb.scripts.config.mjs
file:
format: {
args: ['--write'],
files: ['src', 'lib'],
ignorePath: '.prettierignore'
}
If runFormatter: true
is set in your nhb.commit.config.mjs
, the formatter will be triggered before committing.
See nhb-commit for more details.
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.
pnpm format
🎨 Running Prettier...
# Scanned file-list
✅ Prettier formatting complete!
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.
{
"scripts": {
"lint": "nhb-lint"
}
}
then run via:
pnpm lint
# or
npm run lint
# or
yarn lint
or directly use as:
pnpm nhb-lint
- ✅ Auto‑detects and ensures ESLint configuration (
.eslintrc.cjs
etc.) - ✅ Loads lint config (
folders
,patterns
) fromnhb.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)
In nhb.scripts.config.mjs
:
lint: {
folders: ['src', 'tests'], // optional; default: ["src"]
patterns: ['**/*.ts', '**/*.tsx'] // optional; default: ["**/*.ts"]
}
🚀 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
Run ESLint with the --fix
flag to automatically fix many common issues in your code.
{
"scripts": {
"fix": "nhb-fix"
}
}
then run via:
pnpm fix
# or
npm run fix
# or
yarn fix
or directly use as:
pnpm nhb-fix
- ✅ 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
🚀 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
nhb-fix
use the fix
section in nhb.scripts.config.mjs
:
fix: {
folders: ['src'], // Folders to lint
patterns: ['**/*.ts'] // Glob patterns per folder
}
- 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.
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.
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
In nhb.scripts.config.mjs
:
count: {
defaultPath: '.', // Default path when no input is provided
excludePaths: [ // Directories automatically excluded
'node_modules',
'dist',
'build'
]
}
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]
-
If you enter a file path:
- Must be
.js
,.ts
, or.mjs
- Analyzes only that file
- Must be
-
If you enter a folder path:
- Recursively scans for matching files
- Automatically excludes
node_modules
,dist
,build
- Respects additional
excludePaths
from config
-
If you press Enter:
- Uses
defaultPath
from config (defaults to.
)
- Uses
📦 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
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 } ) |
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
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
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
- 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.
🗑 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.