commit d17645f670c9b54eea1f6ecebc24df5b2489d23a Author: Zhongwei Li Date: Sat Nov 29 18:46:18 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..398bc95 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,12 @@ +{ + "name": "eslint-prettier-husky-config", + "description": "This skill should be used when setting up code quality tooling with ESLint v9 flat config, Prettier formatting, Husky git hooks, lint-staged pre-commit checks, and GitHub Actions CI lint workflow. Apply when initializing linting, adding code formatting, configuring pre-commit hooks, setting up quality gates, or establishing lint CI checks for Next.js or React projects.", + "version": "1.0.0", + "author": { + "name": "Hope Overture", + "email": "support@worldbuilding-app-skills.dev" + }, + "skills": [ + "./skills" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7e5e71c --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# eslint-prettier-husky-config + +This skill should be used when setting up code quality tooling with ESLint v9 flat config, Prettier formatting, Husky git hooks, lint-staged pre-commit checks, and GitHub Actions CI lint workflow. Apply when initializing linting, adding code formatting, configuring pre-commit hooks, setting up quality gates, or establishing lint CI checks for Next.js or React projects. diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..e18a5c9 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,69 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:hopeoverture/worldbuilding-app-skills:plugins/eslint-prettier-husky-config", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "2ef108c1963464507ad1f6580aa16051c68bc6e2", + "treeHash": "cac77eb8189bfd279f73fc484d0e989d320b184fe0890b304f1962704059e980", + "generatedAt": "2025-11-28T10:17:31.845859Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "eslint-prettier-husky-config", + "description": "This skill should be used when setting up code quality tooling with ESLint v9 flat config, Prettier formatting, Husky git hooks, lint-staged pre-commit checks, and GitHub Actions CI lint workflow. Apply when initializing linting, adding code formatting, configuring pre-commit hooks, setting up quality gates, or establishing lint CI checks for Next.js or React projects.", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "ca1c68e4fa0afff31a4b0d158f7ba0f6ba1372ea029379fb4ade3b1c2bdfde7e" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "a13656d618b1830965c25bb636e2a834bb9eb00c348f6bcd284e0237ce98cbd8" + }, + { + "path": "skills/eslint-prettier-husky-config/SKILL.md", + "sha256": "274663d87996b1d4568c17ddd9e5f34f1ca430d2bd4743a6002aaada8487498a" + }, + { + "path": "skills/eslint-prettier-husky-config/references/team-documentation.md", + "sha256": "610ed48cc339aefd357b95b367917e280aa3401f899a3789804dcf497db644c3" + }, + { + "path": "skills/eslint-prettier-husky-config/references/package-json-config.md", + "sha256": "d526105e314f0da9d2225b9ebf0fbe7ca5fca8f17772555ed6046b2cf9e4bc42" + }, + { + "path": "skills/eslint-prettier-husky-config/assets/.prettierignore", + "sha256": "4fa063691a03f470eb47ad0c6ea65e46c0a7d6f79a74b4435c6b0ba3809ec7a4" + }, + { + "path": "skills/eslint-prettier-husky-config/assets/.prettierrc", + "sha256": "a760bf007a9b19ea9b124096a0738725fee6ec7fe240b90a30fa69ce7f6401fe" + }, + { + "path": "skills/eslint-prettier-husky-config/assets/github-workflows-lint.yml", + "sha256": "481ae4357007245f03fe9731407b4eb53dd82d9bbb2c261162d969d7c393efda" + }, + { + "path": "skills/eslint-prettier-husky-config/assets/eslint.config.mjs", + "sha256": "1ee7ba40694955af362c2702f2aa9e34d8fa82971b40624cb1c9ea21fb51f727" + } + ], + "dirSha256": "cac77eb8189bfd279f73fc484d0e989d320b184fe0890b304f1962704059e980" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/eslint-prettier-husky-config/SKILL.md b/skills/eslint-prettier-husky-config/SKILL.md new file mode 100644 index 0000000..7d7abfe --- /dev/null +++ b/skills/eslint-prettier-husky-config/SKILL.md @@ -0,0 +1,224 @@ +--- +name: eslint-prettier-husky-config +description: This skill should be used when setting up code quality tooling with ESLint v9 flat config, Prettier formatting, Husky git hooks, lint-staged pre-commit checks, and GitHub Actions CI lint workflow. Apply when initializing linting, adding code formatting, configuring pre-commit hooks, setting up quality gates, or establishing lint CI checks for Next.js or React projects. +--- + +# ESLint, Prettier, Husky Configuration + +## Overview + +Configure comprehensive code quality tooling for Next.js/React projects using ESLint v9 (flat config), Prettier, Husky git hooks, lint-staged, and CI lint checks. + +## Installation and Configuration Steps + +### 1. Install Dependencies + +Install required packages for ESLint v9, Prettier, and git hooks: + +```bash +npm install -D eslint@^9 @eslint/js eslint-config-prettier eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y prettier husky lint-staged +``` + +For TypeScript projects, add: + +```bash +npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin typescript-eslint +``` + +### 2. Create ESLint Flat Config + +Create `eslint.config.mjs` in project root using the provided template from `assets/eslint.config.mjs`. This flat config format: + +- Uses modern ESLint v9 configuration +- Includes React, React Hooks, and JSX accessibility rules +- Supports TypeScript with type-aware linting +- Ignores Next.js build directories and configuration files + +Customize the configuration based on project needs: +- Adjust `languageOptions.parserOptions` for different ECMAScript versions +- Modify `rules` to match team preferences +- Add additional plugins as needed + +### 3. Create Prettier Configuration + +Create `.prettierrc` in project root using the template from `assets/.prettierrc`. This configuration: + +- Sets 2-space indentation +- Uses single quotes for strings +- Removes trailing commas +- Sets 100-character line width +- Uses Unix line endings + +Adjust formatting rules to match team style guide. + +Create `.prettierignore` using `assets/.prettierignore` to exclude: +- Build directories (.next, dist, out) +- Dependencies (node_modules, package-lock.json) +- Generated files +- Public assets + +### 4. Set Up Husky and Lint-Staged + +Initialize Husky for git hooks: + +```bash +npx husky init +``` + +This creates `.husky/` directory with a `pre-commit` hook. + +Replace the pre-commit hook content with: + +```bash +npx lint-staged +``` + +Add lint-staged configuration to `package.json` using the example from `references/package-json-config.md`: + +```json +{ + "lint-staged": { + "*.{js,jsx,ts,tsx}": [ + "eslint --fix", + "prettier --write" + ], + "*.{json,md,yml,yaml}": [ + "prettier --write" + ] + } +} +``` + +This runs ESLint and Prettier on staged files before each commit. + +### 5. Add Package Scripts + +Add the following scripts to `package.json` (see `references/package-json-config.md` for complete example): + +```json +{ + "scripts": { + "lint": "eslint . --max-warnings 0", + "lint:fix": "eslint . --fix", + "format": "prettier --write .", + "format:check": "prettier --check .", + "prepare": "husky" + } +} +``` + +These scripts enable: +- `npm run lint` - Check for linting errors (fails on warnings) +- `npm run lint:fix` - Auto-fix linting issues +- `npm run format` - Format all files with Prettier +- `npm run format:check` - Check formatting without modifying files +- `prepare` - Automatically set up Husky when installing dependencies + +### 6. Create GitHub Actions Lint Workflow + +Create `.github/workflows/lint.yml` using the template from `assets/github-workflows-lint.yml`. This workflow: + +- Runs on pull requests and pushes to main/master +- Checks out code and sets up Node.js +- Installs dependencies +- Runs both linting and format checks +- Fails CI if any issues are found + +Customize the workflow: +- Adjust Node.js version as needed +- Modify branch names to match repository +- Add caching for faster CI runs + +### 7. Verify Setup + +Test the complete setup: + +1. **Lint check**: Run `npm run lint` to verify ESLint configuration +2. **Format check**: Run `npm run format:check` to verify Prettier configuration +3. **Pre-commit hook**: Make a change and commit to test Husky and lint-staged +4. **CI workflow**: Push to a branch and open a PR to verify GitHub Actions + +Fix any configuration issues: +- Review ESLint errors and adjust rules if needed +- Format all files: `npm run format` +- Commit the configuration changes + +### 8. Team Documentation + +Document the setup for team members (see `references/team-documentation.md` for template): + +- Explain the purpose of each tool +- Provide setup instructions for new developers +- Document how to temporarily bypass hooks (for emergencies only) +- Include troubleshooting steps for common issues + +## Configuration Customization + +### ESLint Rules + +Adjust rule severity in `eslint.config.mjs`: +- `"off"` - Disable rule +- `"warn"` - Warning (doesn't fail CI) +- `"error"` - Error (fails CI) + +Common customizations: +- Disable specific rules: `'react/prop-types': 'off'` +- Adjust rule options: `'max-len': ['error', { code: 120 }]` +- Add project-specific rules + +### Prettier Options + +Modify formatting in `.prettierrc`: +- `printWidth` - Line length limit +- `tabWidth` - Spaces per indentation level +- `semi` - Semicolon preference +- `singleQuote` - Quote style +- `trailingComma` - Trailing comma rules + +### Lint-Staged Configuration + +Customize pre-commit checks in `package.json`: +- Add file type patterns +- Include additional commands (tests, type checking) +- Adjust which files trigger which linters + +Example with type checking: +```json +{ + "lint-staged": { + "*.{ts,tsx}": [ + "eslint --fix", + "prettier --write", + "tsc-files --noEmit" + ] + } +} +``` + +## Troubleshooting + +**ESLint errors on existing code**: Run `npm run lint:fix` then `npm run format` to auto-fix most issues. + +**Husky hooks not running**: Ensure `npm install` was run after Husky initialization. Check `.husky/pre-commit` is executable. + +**CI failing but local passes**: Verify Node.js version matches between local and CI. Check that all dependencies are in `package.json`. + +**Conflicts between ESLint and Prettier**: Ensure `eslint-config-prettier` is last in extends array to disable conflicting ESLint formatting rules. + +## Resources + +### scripts/ + +No executable scripts needed for this skill. + +### references/ + +- `package-json-config.md` - Complete package.json example with all scripts and lint-staged configuration +- `team-documentation.md` - Template for documenting the setup for team members + +### assets/ + +- `eslint.config.mjs` - ESLint v9 flat config template with React, TypeScript, and Next.js support +- `.prettierrc` - Prettier configuration with recommended settings +- `.prettierignore` - Files and directories to exclude from formatting +- `github-workflows-lint.yml` - GitHub Actions workflow for automated lint checks diff --git a/skills/eslint-prettier-husky-config/assets/.prettierignore b/skills/eslint-prettier-husky-config/assets/.prettierignore new file mode 100644 index 0000000..3805da4 --- /dev/null +++ b/skills/eslint-prettier-husky-config/assets/.prettierignore @@ -0,0 +1,33 @@ +# Dependencies +node_modules +package-lock.json +yarn.lock +pnpm-lock.yaml + +# Build outputs +.next +out +dist +build +coverage + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment files +.env*.local + +# Public assets +public/static +public/images + +# Generated files +*.min.js +*.min.css + +# IDE +.vscode +.idea diff --git a/skills/eslint-prettier-husky-config/assets/.prettierrc b/skills/eslint-prettier-husky-config/assets/.prettierrc new file mode 100644 index 0000000..0a22e73 --- /dev/null +++ b/skills/eslint-prettier-husky-config/assets/.prettierrc @@ -0,0 +1,13 @@ +{ + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "es5", + "printWidth": 100, + "arrowParens": "always", + "endOfLine": "lf", + "bracketSpacing": true, + "jsxSingleQuote": false, + "proseWrap": "preserve" +} diff --git a/skills/eslint-prettier-husky-config/assets/eslint.config.mjs b/skills/eslint-prettier-husky-config/assets/eslint.config.mjs new file mode 100644 index 0000000..8e65ae2 --- /dev/null +++ b/skills/eslint-prettier-husky-config/assets/eslint.config.mjs @@ -0,0 +1,112 @@ +import js from '@eslint/js'; +import react from 'eslint-plugin-react'; +import reactHooks from 'eslint-plugin-react-hooks'; +import jsxA11y from 'eslint-plugin-jsx-a11y'; +import tseslint from 'typescript-eslint'; +import prettier from 'eslint-config-prettier'; + +export default [ + // Ignore patterns + { + ignores: [ + '.next/**', + 'out/**', + 'dist/**', + 'build/**', + 'node_modules/**', + '*.config.js', + '*.config.mjs', + 'coverage/**', + ], + }, + + // Base JavaScript config + js.configs.recommended, + + // TypeScript config + ...tseslint.configs.recommended, + + // React plugin config + { + files: ['**/*.{js,jsx,ts,tsx}'], + plugins: { + react, + 'react-hooks': reactHooks, + 'jsx-a11y': jsxA11y, + }, + languageOptions: { + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + window: 'readonly', + document: 'readonly', + navigator: 'readonly', + console: 'readonly', + setTimeout: 'readonly', + clearTimeout: 'readonly', + setInterval: 'readonly', + clearInterval: 'readonly', + Promise: 'readonly', + fetch: 'readonly', + FormData: 'readonly', + Headers: 'readonly', + Request: 'readonly', + Response: 'readonly', + URL: 'readonly', + URLSearchParams: 'readonly', + process: 'readonly', + }, + }, + settings: { + react: { + version: 'detect', + }, + }, + rules: { + // React rules + 'react/react-in-jsx-scope': 'off', // Not needed in Next.js + 'react/prop-types': 'off', // Using TypeScript for prop validation + 'react/jsx-uses-react': 'error', + 'react/jsx-uses-vars': 'error', + 'react/jsx-key': 'error', + 'react/no-array-index-key': 'warn', + 'react/no-unescaped-entities': 'warn', + + // React Hooks rules + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + + // Accessibility rules + 'jsx-a11y/alt-text': 'warn', + 'jsx-a11y/anchor-is-valid': 'warn', + 'jsx-a11y/aria-props': 'warn', + 'jsx-a11y/aria-unsupported-elements': 'warn', + 'jsx-a11y/role-has-required-aria-props': 'warn', + + // TypeScript rules + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + }, + ], + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/explicit-module-boundary-types': 'off', + + // General rules + 'no-console': ['warn', { allow: ['warn', 'error'] }], + 'no-unused-vars': 'off', // Using TypeScript version instead + 'prefer-const': 'error', + 'no-var': 'error', + }, + }, + + // Prettier config (must be last to override other formatting rules) + prettier, +]; diff --git a/skills/eslint-prettier-husky-config/assets/github-workflows-lint.yml b/skills/eslint-prettier-husky-config/assets/github-workflows-lint.yml new file mode 100644 index 0000000..f0fea0f --- /dev/null +++ b/skills/eslint-prettier-husky-config/assets/github-workflows-lint.yml @@ -0,0 +1,30 @@ +name: Lint + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + 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: Run ESLint + run: npm run lint + + - name: Check formatting + run: npm run format:check diff --git a/skills/eslint-prettier-husky-config/references/package-json-config.md b/skills/eslint-prettier-husky-config/references/package-json-config.md new file mode 100644 index 0000000..5f27d4e --- /dev/null +++ b/skills/eslint-prettier-husky-config/references/package-json-config.md @@ -0,0 +1,101 @@ +# Package.json Configuration Reference + +## Complete Scripts and Lint-Staged Configuration + +Add these sections to your `package.json`: + +```json +{ + "name": "your-project", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint . --max-warnings 0", + "lint:fix": "eslint . --fix", + "format": "prettier --write .", + "format:check": "prettier --check .", + "prepare": "husky" + }, + "lint-staged": { + "*.{js,jsx,ts,tsx}": [ + "eslint --fix", + "prettier --write" + ], + "*.{json,md,yml,yaml,css,scss}": [ + "prettier --write" + ] + }, + "devDependencies": { + "eslint": "^9.0.0", + "@eslint/js": "^9.0.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-react": "^7.35.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-jsx-a11y": "^6.9.0", + "@typescript-eslint/parser": "^7.0.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "typescript-eslint": "^7.0.0", + "prettier": "^3.3.0", + "husky": "^9.0.0", + "lint-staged": "^15.2.0" + } +} +``` + +## Script Descriptions + +- **lint**: Runs ESLint on entire codebase with zero warning tolerance (fails CI on warnings) +- **lint:fix**: Automatically fixes ESLint issues where possible +- **format**: Formats all files in project with Prettier +- **format:check**: Checks formatting without modifying files (good for CI) +- **prepare**: npm lifecycle hook that runs after `npm install` to set up Husky + +## Lint-Staged Configuration + +The `lint-staged` object defines which commands run on which file types during pre-commit: + +- JavaScript/TypeScript files: Run ESLint with auto-fix, then Prettier +- Other files (JSON, Markdown, YAML, CSS): Run only Prettier + +### Adding Type Checking + +For stricter pre-commit checks, add TypeScript type checking: + +```json +{ + "lint-staged": { + "*.{ts,tsx}": [ + "eslint --fix", + "prettier --write", + "bash -c 'tsc --noEmit'" + ], + "*.{js,jsx}": [ + "eslint --fix", + "prettier --write" + ] + } +} +``` + +Note: Type checking all staged files can slow down commits. Consider using it selectively. + +### Adding Tests + +To run tests on staged files: + +```json +{ + "lint-staged": { + "*.{ts,tsx,js,jsx}": [ + "eslint --fix", + "prettier --write", + "jest --bail --findRelatedTests" + ] + } +} +``` + +The `--findRelatedTests` flag runs only tests related to changed files. diff --git a/skills/eslint-prettier-husky-config/references/team-documentation.md b/skills/eslint-prettier-husky-config/references/team-documentation.md new file mode 100644 index 0000000..cc8f166 --- /dev/null +++ b/skills/eslint-prettier-husky-config/references/team-documentation.md @@ -0,0 +1,147 @@ +# Code Quality Setup - Team Documentation + +## Overview + +This project uses automated code quality tools to maintain consistent code style and catch errors early: + +- **ESLint** - Identifies code quality issues and potential bugs +- **Prettier** - Automatically formats code to consistent style +- **Husky** - Runs quality checks before commits via git hooks +- **lint-staged** - Only checks files you're committing (fast!) +- **GitHub Actions** - Verifies code quality in CI + +## For New Team Members + +### First Time Setup + +After cloning the repository, run: + +```bash +npm install +``` + +This automatically sets up Husky git hooks via the `prepare` script. + +### Daily Workflow + +When you make changes and commit: + +1. Stage your files: `git add .` +2. Commit: `git commit -m "your message"` +3. **Pre-commit hook automatically runs** and checks your staged files +4. If checks pass, commit succeeds +5. If checks fail, fix the issues and try again + +### Manual Quality Checks + +Run these commands any time: + +```bash +# Check for linting errors +npm run lint + +# Auto-fix linting issues +npm run lint:fix + +# Format all files +npm run format + +# Check formatting (doesn't modify files) +npm run format:check +``` + +### IDE Integration + +**Recommended**: Install ESLint and Prettier extensions in your editor: + +- **VS Code**: Install "ESLint" and "Prettier - Code formatter" extensions +- **WebStorm/IntelliJ**: Enable ESLint and Prettier in Settings > Languages & Frameworks + +Configure format on save in your editor for the best experience. + +## Common Scenarios + +### Pre-commit Hook Fails + +**Linting errors**: Review the errors shown. Run `npm run lint:fix` to auto-fix many issues. + +**Formatting issues**: Run `npm run format` to format all files, then try committing again. + +**Type errors**: Fix TypeScript errors shown in the output. The hook prevents commits with type errors. + +### Bypassing Hooks (Emergency Only) + +In rare cases where you need to commit despite failing checks: + +```bash +git commit --no-verify -m "your message" +``` + +**Warning**: Only use this for emergencies. The CI will still fail if code quality checks don't pass. + +### Updating ESLint Rules + +If you encounter a rule that doesn't make sense for your use case: + +1. Discuss with the team first +2. Update `eslint.config.mjs` with the agreed change +3. Run `npm run lint` to verify the change works +4. Commit the configuration change + +## Troubleshooting + +### Hooks Not Running + +If pre-commit hooks don't run when you commit: + +```bash +# Reinstall Husky +rm -rf .husky +npm run prepare +``` + +Verify `.husky/pre-commit` exists and is executable. + +### ESLint Configuration Errors + +If ESLint fails to run with configuration errors: + +```bash +# Check your Node version (should be 18+) +node --version + +# Reinstall dependencies +rm -rf node_modules package-lock.json +npm install +``` + +### Conflicts Between Tools + +If ESLint and Prettier report conflicting issues: + +- Prettier should always win for formatting issues +- Check that `eslint-config-prettier` is installed +- Verify it's last in the config chain to disable conflicting ESLint rules + +### CI Passing Locally But Failing in GitHub Actions + +- Ensure you've committed all configuration files +- Verify Node.js version matches between local and CI +- Check that all devDependencies are in package.json +- Run `npm run lint` and `npm run format:check` locally before pushing + +## Configuration Files + +- `eslint.config.mjs` - ESLint rules and configuration +- `.prettierrc` - Prettier formatting rules +- `.prettierignore` - Files Prettier should skip +- `.husky/pre-commit` - Pre-commit hook that runs lint-staged +- `package.json` - Contains lint-staged configuration and scripts +- `.github/workflows/lint.yml` - CI workflow for automated checks + +## Additional Resources + +- [ESLint Documentation](https://eslint.org/docs/latest/) +- [Prettier Documentation](https://prettier.io/docs/en/) +- [Husky Documentation](https://typicode.github.io/husky/) +- [lint-staged Documentation](https://github.com/lint-staged/lint-staged)