Markdown Converter
Agent skill for markdown-converter
Comprehensive configuration templates and guidance for setting up TypeScript projects with modern tooling, testing frameworks, and code quality enforcement.
Sign in to like and favorite skills
Comprehensive configuration templates and guidance for setting up TypeScript projects with modern tooling, testing frameworks, and code quality enforcement.
This skill provides standardized configurations and best practices for TypeScript projects, including:
Use this skill when:
When using this skill, Claude will ask:
Recommended directory structure:
project-root/ ├── src/ # TypeScript source files │ ├── **/*.ts │ └── **/*.tsx ├── tests/ # Test files │ ├── **/*.test.ts # Vitest unit tests (if using Vitest) │ └── **/*.spec.ts # Test files (Vitest or Playwright) ├── dist/ # Compiled output (if not using bundler) ├── .husky/ # Git hooks (if enabled) │ └── pre-commit ├── .github/ # GitHub Actions workflows │ └── workflows/ │ └── checks.yml ├── tsconfig.json # TypeScript config ├── biome.json # Biome config (if using Biome) ├── eslint.config.js # ESLint config (if using ESLint) ├── .prettierrc.json # Prettier config (if using Prettier) ├── vitest.config.js # Vitest config (if using Vitest) ├── playwright.config.ts # Playwright config (if using Playwright) ├── Makefile # Common operations └── package.json
{ "compilerOptions": { "target": "ES2022", "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "forceConsistentCasingInFileNames": true }, "include": ["src"] }
Key settings for Vite:
"moduleResolution": "bundler" - Modern bundler-aware resolution"noEmit": true - Vite handles compilation, not tsc"allowImportingTsExtensions": true - Import .ts files directly"isolatedModules": true - Required for bundlers{ "compilerOptions": { "target": "ES2022", "module": "ES2022", "moduleResolution": "node", "esModuleInterop": true, "strict": true, "noImplicitAny": true, "strictNullChecks": true, "noUnusedLocals": true, "noUnusedParameters": true, "lib": ["ES2022"], "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "outDir": "dist", "rootDir": "src", "declaration": true, "resolveJsonModule": true }, "include": ["src/**/*.ts"], "exclude": ["node_modules", "dist"] }
{ "compilerOptions": { "target": "ES2020", "module": "CommonJS", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }
When to use CommonJS:
Configuration (biome.json):
{ "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "organizeImports": { "enabled": true }, "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2, "lineWidth": 120, "lineEnding": "lf" }, "linter": { "enabled": true, "rules": { "recommended": true, "suspicious": { "noExplicitAny": "warn" }, "style": { "useConst": "error", "noNonNullAssertion": "warn" } } }, "javascript": { "formatter": { "quoteStyle": "single", "semicolons": "asNeeded", "trailingCommas": "es5" } }, "files": { "ignore": [ "dist", "node_modules", "test-results", "playwright-report", "*.config.js", "*.config.ts" ] } }
Package.json scripts:
{ "scripts": { "lint": "biome check .", "lint:fix": "biome check --write .", "format": "biome format --write .", "check": "biome check . && tsc --noEmit" } }
Dependencies:
npm install --save-dev @biomejs/biome
Biome advantages:
Code style:
ESLint Configuration (eslint.config.js):
import eslint from '@eslint/js' import tseslint from '@typescript-eslint/eslint-plugin' import tsParser from '@typescript-eslint/parser' export default [ eslint.configs.recommended, { files: ['**/*.ts', '**/*.js'], languageOptions: { parser: tsParser, ecmaVersion: 2020, sourceType: 'module', globals: { // Browser globals window: 'readonly', document: 'readonly', console: 'readonly', // Node globals process: 'readonly', module: 'readonly', require: 'readonly', __dirname: 'readonly' } }, plugins: { '@typescript-eslint': tseslint }, rules: { ...tseslint.configs.recommended.rules, '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], '@typescript-eslint/no-explicit-any': 'warn', 'no-console': 'warn', 'semi': ['error', 'never'], 'quotes': ['error', 'single', { avoidEscape: true }], 'comma-dangle': ['error', 'never'] } }, { files: ['**/*.test.js', '**/*.test.ts'], rules: { 'no-console': 'off' } } ]
Prettier Configuration (.prettierrc.json):
{ "semi": false, "singleQuote": true, "trailingComma": "none", "printWidth": 100, "tabWidth": 2, "arrowParens": "avoid" }
Package.json scripts:
{ "scripts": { "lint": "eslint src/**/*.{js,ts}", "lint:fix": "eslint src/**/*.{js,ts} --fix", "lint:errors-only": "eslint src/**/*.{js,ts} --quiet", "format": "prettier --write src/**/*.{js,ts}", "format:check": "prettier --check src/**/*.{js,ts}", "check": "npm run typecheck && npm run lint && npm run format:check" } }
Dependencies:
npm install --save-dev \ eslint @eslint/js \ @typescript-eslint/eslint-plugin \ @typescript-eslint/parser \ prettier
Code style:
When to use:
Package.json scripts:
{ "scripts": { "check": "tsc --noEmit" } }
Note: TypeScript's strict mode catches many issues that linters would, but you lose style consistency enforcement.
When to use: Unit testing, integration testing, API testing (no browser needed).
Configuration (vitest.config.js):
import {defineConfig} from 'vitest/config' export default defineConfig({ test: { environment: 'jsdom', globals: true, setupFiles: ['./tests/setup.js'], include: ['./tests/**/*.test.js', './tests/**/*.test.ts', './tests/**/*.spec.ts'], coverage: { provider: 'v8', reporter: ['text', 'json', 'html'] } } })
Note: Vitest works without a config file - it will auto-discover tests. Config is optional for customization.
Package.json scripts:
{ "scripts": { "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", "test:ui": "vitest --ui" } }
Dependencies:
npm install --save-dev vitest @vitest/coverage-v8
When to use: E2E testing, browser testing, visual testing.
Configuration (playwright.config.ts):
import { defineConfig, devices } from '@playwright/test' export default defineConfig({ testDir: './tests', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: 'html', use: { baseURL: process.env.BASE_URL || 'http://localhost:3000', trace: 'on-first-retry', screenshot: 'only-on-failure', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, ], webServer: process.env.BASE_URL ? undefined : { command: 'npm run preview', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, }, })
Package.json scripts:
{ "scripts": { "test": "playwright test", "test:headed": "playwright test --headed", "test:ui": "playwright test --ui" } }
Dependencies:
npm install --save-dev @playwright/test
When to use: Comprehensive testing strategy (fast unit tests + thorough E2E tests).
Testing strategy:
.test.ts files → Vitest (unit tests).spec.ts files → Playwright (E2E tests)Package.json scripts:
{ "scripts": { "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", "test:ui": "vitest --ui", "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui", "test:e2e:report": "playwright show-report" } }
Setup Husky:
npm install --save-dev husky npx husky init
Pre-commit hook (.husky/pre-commit):
#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" npm run quality:commit
Package.json scripts:
For Biome:
{ "scripts": { "quality": "npm run check && npm run test", "quality:commit": "biome check . && tsc --noEmit && npm run test", "prepare": "husky" } }
For ESLint+Prettier:
{ "scripts": { "quality": "npm run typecheck && npm run lint && npm run format:check && npm run test", "quality:commit": "npm run typecheck && npm run lint:errors-only && npm run test", "prepare": "husky" } }
For minimal (no linting):
{ "scripts": { "quality": "npm run typecheck && npm run test", "quality:commit": "tsc --noEmit && npm run test", "prepare": "husky" } }
What runs in pre-commit:
What NOT to run in pre-commit:
Common Makefile targets:
.PHONY: help install build test clean lint format check help: @echo "Available targets:" @echo " install - Install dependencies" @echo " build - Build the project" @echo " test - Run tests" @echo " clean - Clean build artifacts" @echo " lint - Run linting" @echo " format - Format code" @echo " check - Run all quality checks" install: npm ci build: npm run build test: npm run test clean: rm -rf dist node_modules lint: npm run lint format: npm run format check: npm run quality
Basic CI workflow (.github/workflows/checks.yml):
name: Checks on: push: branches-ignore: - main pull_request: branches: - main permissions: read-all jobs: quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: Type check run: npm run typecheck - name: Lint run: npm run lint if: hashFiles('biome.json', 'eslint.config.js') != '' - name: Test run: npm run test if: hashFiles('vitest.config.js', 'playwright.config.ts') != ''
For ES Modules + Biome + Vitest:
{ "name": "my-typescript-project", "version": "1.0.0", "type": "module", "scripts": { "dev": "your-dev-command", "build": "tsc", "typecheck": "tsc --noEmit", "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", "lint": "biome check .", "lint:fix": "biome check --write .", "format": "biome format --write .", "check": "biome check . && tsc --noEmit", "quality": "npm run check && npm run test", "quality:commit": "biome check . && tsc --noEmit && npm run test", "prepare": "husky" }, "devDependencies": { "@biomejs/biome": "^1.9.0", "@types/node": "^22.0.0", "@vitest/coverage-v8": "^2.1.0", "husky": "^9.0.0", "typescript": "^5.6.0", "vitest": "^2.1.0" } }
For CommonJS + No Linting + Vitest:
{ "name": "my-typescript-project", "version": "1.0.0", "scripts": { "build": "tsc", "test": "vitest", "coverage": "vitest run --coverage", "typecheck": "tsc --noEmit", "quality": "npm run typecheck && npm run test", "quality:commit": "tsc --noEmit && npm run test", "prepare": "husky" }, "devDependencies": { "@types/node": "^22.0.0", "@vitest/coverage-v8": "^2.1.0", "husky": "^9.0.0", "typescript": "^5.6.0", "vitest": "^2.1.0" } }
npm init -y npm install --save-dev typescript
For ES Modules (recommended):
npm pkg set type=module
For CommonJS:
No action needed (default)
npx tsc --init
Then replace with the appropriate config from this skill.
Option A: Biome (recommended)
npm install --save-dev @biomejs/biome npx @biomejs/biome init
Option B: ESLint + Prettier
npm install --save-dev \ eslint @eslint/js \ @typescript-eslint/eslint-plugin \ @typescript-eslint/parser \ prettier
Option C: None
Skip this step
Option A: Vitest
npm install --save-dev vitest @vitest/coverage-v8
Option B: Playwright
npm init playwright@latest
Option C: Both
npm install --save-dev vitest @vitest/coverage-v8 @playwright/test npm init playwright@latest
npm install --save-dev husky npx husky init echo "npm run quality:commit" > .husky/pre-commit chmod +x .husky/pre-commit
Create a
Makefile with the targets shown above.
Create
.github/workflows/checks.yml with the workflow shown above.
ES Modules (recommended for new projects):
CommonJS (for legacy compatibility):
noUnusedLocals and noUnusedParametersany types (linters warn about them)_ if needed| Criteria | Biome | ESLint+Prettier | None |
|---|---|---|---|
| Speed | Much faster | Slower | Fastest |
| Simplicity | Single tool | Two tools | No tools |
| Ecosystem | Growing | Mature, extensive | N/A |
| Style enforcement | Excellent | Excellent | Manual |
| Type safety | Via rules | Via rules | TypeScript only |
| Criteria | ES Modules | CommonJS |
|---|---|---|
| Modern | Yes | No |
| Bundler support | Excellent | Good |
| Node.js compat | Node 12+ | All versions |
| Future-proof | Yes | Legacy |
| Criteria | Vitest | Playwright | Both |
|---|---|---|---|
| Unit testing | Excellent | N/A | Excellent |
| E2E testing | N/A | Excellent | Excellent |
| Speed | Fast | Slower | Mixed |
| Setup | Simple | Moderate | Complex |
Solution: Ensure
"type": "module" is in package.json and use .js extension for config files.
Solution: Biome works out of the box with TypeScript. Ensure
biome.json exists and @biomejs/biome is installed.
Solution: Verify
@typescript-eslint/parser is specified in languageOptions.parser.
Solution: Use
quality:commit (fast) instead of quality (comprehensive). Remove E2E tests from pre-commit.
Solution: Vitest auto-discovers tests. Ensure test files match patterns:
**/*.{test,spec}.{js,ts}.
Solution: Ensure
.husky/pre-commit is executable: chmod +x .husky/pre-commit.
Solution: Ensure Makefile uses tabs (not spaces) for indentation.
declaration: true