Code Quality
This template includes multiple tools to maintain code quality and consistency.
Overview
| Tool | Purpose | Script |
|---|---|---|
| ESLint | Linting TypeScript/JavaScript | pnpm run lint |
| Prettier | Code formatting | pnpm run format |
| publint | Validate package.json exports | pnpm run lint:package |
| knip | Detect unused code and dependencies | pnpm run lint:deps |
| markdownlint | Lint Markdown files | pnpm run lint:md |
ESLint
ESLint 9 uses the flat configuration format in eslint.config.mjs.
Configuration
The config includes:
- Ignores — Skip
dist/,coverage/,.vitepress/cache,api-generated/ - Base rules — ESLint recommended rules
- TypeScript rules —
typescript-eslintrecommended, strict, and stylistic - Prettier compatibility — Disables formatting rules that conflict with Prettier
Running ESLint
# Check for errors
pnpm run lint
# ESLint can auto-fix some issues
pnpm exec eslint . --fixCommon Issues
Unused variables:
// Error: 'x' is defined but never used
const x = 1;
// Fix: Remove or use the variable
// Or prefix with underscore if intentionally unused
const _x = 1;Type assertions:
// Warning: Avoid 'as' type assertions
const value = data as string;
// Prefer type guards or generics
function isString(val: unknown): val is string {
return typeof val === "string";
}Prettier
Prettier handles code formatting with minimal configuration.
Configuration
Prettier config is in .prettierrc. The template uses defaults with these considerations:
.prettierignoreexcludes generated files- ESLint config includes
eslint-config-prettierto avoid conflicts
Running Prettier
# Check formatting
pnpm run format
# Fix formatting
pnpm run format:writeEditor Integration
For best experience, configure your editor to format on save:
VS Code (.vscode/settings.json):
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}publint
publint validates that your package can be correctly consumed by different tools and runtimes.
What It Checks
- Export paths resolve to existing files
- Types are correctly ordered (types before default)
main,module, andtypesfields are consistent withexports- Package can be imported in Node.js ESM and CJS modes
Running publint
# Requires dist/ to exist
pnpm run build
pnpm run lint:packageCommon Errors
Missing dist files:
✖ dist/index.js does not existFix: Run pnpm run build first.
Incorrect types order:
✖ types should come before default in exportsFix: In package.json exports, place "types" before "default":
{
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}knip
knip finds unused dependencies, exports, and files.
Configuration
Config is in knip.json:
{
"ignore": ["docs/.vitepress/**", "docs/api-generated/**", "dist/**"]
}Running knip
pnpm run lint:depsUnderstanding Output
Unused dependencies:
Unused dependencies:
- lodashFix: Remove from package.json or use the dependency.
Unused exports:
Unused exports:
- src/utils.ts: helperFunctionFix: Remove the export or use it internally.
False positives:
Some exports may be intentionally public but unused internally. Add to knip config:
{
"ignore": ["..."],
"ignoreDependencies": ["some-dev-tool"],
"entry": ["src/index.ts"]
}markdownlint
markdownlint enforces consistent Markdown formatting.
Configuration
The lint script excludes:
node_modules/docs/api-generated/(auto-generated)
Running markdownlint
pnpm run lint:mdCommon Rules
| Rule | Description | Fix |
|---|---|---|
| MD001 | Heading levels should increment | Don't skip h1 to h3 |
| MD012 | Multiple consecutive blank lines | Use single blank lines |
| MD013 | Line length | Wrap long lines or disable rule |
| MD022 | Headings should be surrounded by blanks | Add blank lines around headings |
| MD032 | Lists should be surrounded by blanks | Add blank lines around lists |
Disabling Rules
To disable a rule inline:
<!-- markdownlint-disable MD013 -->
This very long line is allowed because we disabled the line length rule for this specific case.
<!-- markdownlint-enable MD013 -->Pre-commit Quality Checks
lint-staged runs on staged files before each commit:
{
"lint-staged": {
"*.{ts,tsx,js,mjs,cjs}": ["eslint --fix", "prettier --write"],
"*.{md,json,yml,yaml}": ["prettier --write"]
}
}This ensures:
- TypeScript/JavaScript files are linted and formatted
- Markdown and config files are formatted
CI Quality Checks
The CI workflow runs all quality checks:
pnpm run lint— ESLintpnpm run typecheck— TypeScriptpnpm run test— Vitestpnpm run build— tsuppnpm run lint:package— publintpnpm run lint:deps— knippnpm run lint:md— markdownlint
All checks must pass for the CI to succeed.