bdg-tooling
v1.5.1
Published
Shared tooling configs for TypeScript projects — Biome, tsconfig, commitlint, lint-staged, husky.
Readme
bdg-tooling
Shared tooling configuration package for TypeScript projects.
Provides zero-magic, plain-object exports for:
- tsconfig presets — node, library (ESM), react, nextjs, nestjs
- Biome — formatter + linter configs
- commitlint — Conventional Commits rule set
- lint-staged — Biome runner (auto-fix + enforce on staged files)
- CLI —
npx bdg-tooling initscaffolds a consumer project interactively
Project structure
bdg-tooling/
├── biome/ Biome configs (base.json, node.json, react.json, nestjs.json)
├── commitlint/ commitlint config (index.js)
├── lint-staged/ lint-staged config (biome.js)
├── tsconfig/ tsconfig presets (base, node, node-cjs, library, react, nextjs, nestjs)
├── src/
│ └── cli/
│ ├── init.ts CLI entry point — main()
│ ├── types.ts Shared types (InitOptions, ProjectType)
│ ├── steps/
│ │ ├── prompt.ts Interactive prompts, preset detection
│ │ ├── write-configs.ts Config file writers (tsconfig, biome, commitlint, lint-staged, .gitignore)
│ │ └── setup-hooks.ts Dependency install, Husky setup
│ └── utils/
│ ├── fs.ts File helpers (writeFileSafe, isEsmPackage, detectEslint, patchPackageJson)
│ ├── logger.ts Terminal output (log.success, log.warn, log.step, …)
│ └── shell.ts Shell helpers (detectPackageManager, run, buildInstallCommand)
├── dist/ Compiled CLI output — generated by `pnpm build`, not committed
├── biome.json Biome config for this repo (dev only)
├── tsconfig.jsonc TypeScript config for type-checking (dev only)
└── tsconfig.build.jsonc TypeScript config for compiling dist/ (dev only)The biome/, commitlint/, lint-staged/, tsconfig/, and dist/ directories
are what gets published to npm. src/ and dev config files are excluded from the tarball.
Quick start — CLI
The fastest way to configure a new project:
npx bdg-tooling init
pnpm dlx bdg-tooling initThe CLI will interactively:
- Ask which project type (node / library / react / nextjs / nestjs)
- Ask which tsconfig file to patch (or offer to create one)
- Ask which package manager to use (auto-detected from lock file)
- Ask whether to install peer dependencies now
- Ask whether to set up Husky git hooks
- Ask whether to add commitlint (Conventional Commits)
- Ask whether to add lint-staged (Biome on staged files)
- Write all config files (never overwrites existing ones)
- Install peer dependencies
- Initialize Husky with
pre-commitandcommit-msghooks
Installation
pnpm add -D bdg-tooling typescript @biomejs/biomeOptional (needed if you want Husky + commitlint):
pnpm add -D husky lint-staged @commitlint/cli @commitlint/config-conventionalManual setup
tsconfig
Extend the relevant preset in your tsconfig.json:
// Node.js app (ESM)
{ "extends": "bdg-tooling/tsconfig/node" }
// Node.js app (CommonJS)
{ "extends": "bdg-tooling/tsconfig/node-cjs" }
// ESM library
{ "extends": "bdg-tooling/tsconfig/library" }
// React / Vite app
{ "extends": "bdg-tooling/tsconfig/react" }
// Next.js App Router
{ "extends": "bdg-tooling/tsconfig/nextjs" }
// NestJS app
{ "extends": "bdg-tooling/tsconfig/nestjs" }All presets extend bdg-tooling/tsconfig/base, which enables all
strict flags. Override any compiler option locally:
{
"extends": "bdg-tooling/tsconfig/node",
"compilerOptions": {
"outDir": "./build"
},
"include": ["src"]
}Preset summary
| Preset | target | module | moduleResolution | jsx | emit |
|-------------|---------|-------------|------------------|-----------|-------------------|
| base | — | — | bundler | — | decl + sourcemaps |
| node | ES2022 | NodeNext | NodeNext | — | emits JS |
| node-cjs | ES2022 | CommonJS | node | — | emits JS |
| library | ES2020 | ESNext | bundler | — | declarations only |
| react | ES2020 | ESNext | bundler | react-jsx | noEmit |
| nextjs | ES2017 | ESNext | bundler | preserve | noEmit, incremental|
| nestjs | ES2022 | CommonJS | node | — | emits JS |
Preset details
base — the foundation all other presets extend.
Enables the full strict suite (strict, noImplicitOverride, noImplicitReturns,
noFallthroughCasesInSwitch, noUnusedLocals, noUnusedParameters,
useUnknownInCatchVariables, exactOptionalPropertyTypes) plus
verbatimModuleSyntax, isolatedModules, resolveJsonModule.
Emits declarations and sourcemaps by default (declaration, declarationMap,
sourceMap). Use moduleResolution: "bundler" as the default — individual
presets override this where needed. Does not set target or module; those are
always set by the consuming preset.
node — Node.js ESM application ("type": "module" in package.json).
target: ES2022, module: NodeNext, moduleResolution: NodeNext — these three
must match for Node's native ESM loader to work correctly. Emits JS (set outDir
in your own tsconfig). Use this for services, CLIs, and scripts that run directly
on Node.
node-cjs — Node.js CommonJS application (no "type": "module").
Same as node but module: CommonJS, moduleResolution: node, and
verbatimModuleSyntax: false (the CJS emit format is incompatible with
verbatim module syntax). Use this when you need require() output, e.g. for
legacy tooling or Jest without ESM transform.
library — ESM library distributed to consumers via npm.
target: ES2020, module: ESNext, moduleResolution: bundler.
emitDeclarationOnly: true — your bundler (tsup, rollup, etc.) handles JS output;
TypeScript only emits .d.ts files into dist/types/. Set outDir is pre-set to
dist but you will likely want to override declarationDir to match your bundler
output structure.
react — React application built with Vite or Create React App.
target: ES2020, DOM + DOM.Iterable libs, jsx: react-jsx with
jsxImportSource: react. noEmit: true — Vite handles all transpilation and
bundling; TypeScript is used for type-checking only. Run tsc --noEmit in CI.
nextjs — Next.js App Router project.
target: ES2017 (Next.js transpiles down for broad browser support), DOM libs,
jsx: preserve (Next.js/SWC handles JSX transform), noEmit: true, incremental:
true (speeds up repeated tsc calls), plugins: [{ "name": "next" }] (enables
the Next.js TypeScript plugin for App Router diagnostics). Requires
next to be installed.
nestjs — NestJS application.
target: ES2022, module: CommonJS, moduleResolution: node — matches NestJS's
default build output. experimentalDecorators: true and emitDecoratorMetadata:
true are required for NestJS's decorator-based DI system. strictPropertyInitialization:
false is disabled because injected class properties are initialised by the IoC
container, not in the constructor. verbatimModuleSyntax: false and noEmit: false
since NestJS emits CommonJS modules directly via tsc.
Biome
Reference the config from your biome.json:
// Node.js project
{ "extends": ["bdg-tooling/biome/node"] }
// NestJS project
{ "extends": ["bdg-tooling/biome/nestjs"] }
// React / Vite project
{ "extends": ["bdg-tooling/biome/react"] }
// Base only (no env-specific overrides)
{ "extends": ["bdg-tooling/biome/base"] }Override any rule locally — plain JSON spread semantics apply:
{
"extends": ["bdg-tooling/biome/node"],
"linter": {
"rules": {
"suspicious": {
"noConsole": "warn"
}
}
}
}What the configs enforce
base.json:
- Tab indent, double quotes, trailing commas, semicolons
- Strict linter: recommended + nursery rules enabled
- Banned:
any, unsafeascasts,namespace,dangerouslySetInnerHTML
node.json (extends base):
noConsole→ off (Node scripts log freely)useNodejsImportProtocol→ error (enforcesnode:fsstyle imports)
nestjs.json (standalone, same rules as node):
noConsole→ off (NestJS services use logger classes but console is unrestricted)useNodejsImportProtocol→ error
react.json (extends base):
- JSX runtime set to
reactClassic noDangerouslySetInnerHtml→ error
commitlint
// commitlint.config.js
export { default } from "bdg-tooling/commitlint";Enforces Conventional Commits with
types: feat, fix, docs, style, refactor, perf, test, build,
ci, chore, revert.
lint-staged
// lint-staged.config.js
export { default } from "bdg-tooling/lint-staged/biome";Runs biome check --write on staged files to auto-fix, then re-checks and
fails the commit if any errors remain — same behaviour as npx biome check ..
Husky + git hooks
After installing Husky (pnpm add -D husky) run:
pnpm exec husky initThen set up the hooks:
# .husky/pre-commit
pnpm exec lint-staged
# .husky/commit-msg
pnpm exec commitlint --edit "$1"Add the prepare script to package.json:
{
"scripts": {
"prepare": "husky"
}
}Exports reference
| Import path | Description |
|--------------------------------|--------------------------------------|
| bdg-tooling/tsconfig/base | Strict base tsconfig (no target) |
| bdg-tooling/tsconfig/node | Node.js ESM app preset |
| bdg-tooling/tsconfig/node-cjs| Node.js CommonJS app preset |
| bdg-tooling/tsconfig/library | ESM library preset |
| bdg-tooling/tsconfig/react | React / Vite app preset |
| bdg-tooling/tsconfig/nextjs | Next.js App Router preset |
| bdg-tooling/tsconfig/nestjs | NestJS app preset |
| bdg-tooling/biome/base | Biome base config |
| bdg-tooling/biome/node | Biome config for Node.js |
| bdg-tooling/biome/react | Biome config for React |
| bdg-tooling/biome/nestjs | Biome config for NestJS |
| bdg-tooling/commitlint | commitlint Conventional Commits cfg |
| bdg-tooling/lint-staged/biome| lint-staged runner (Biome only) |
Contributing
pnpm install
pnpm build # compile TypeScript → dist/
pnpm typecheck # type-check without emitting
pnpm lint # Biome check
pnpm lint:fix # Biome check --write (auto-fix)License
MIT
