diff --git a/.github/workflows/publish-react.yml b/.github/workflows/publish-react.yml new file mode 100644 index 0000000..527f583 --- /dev/null +++ b/.github/workflows/publish-react.yml @@ -0,0 +1,30 @@ +name: Publish (React) + +on: + push: + tags: + - react-v* + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + + # GitHub Packages 배포 + - name: Publish to GitHub Packages + run: | + echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc + yarn publish:react --registry=https://npm.pkg.github.com/ + + # npm 공용 레지스트리에 배포 + - name: Publish to npm + run: | + echo "//registry.npmjs.org/:_authToken=${{secrets.NPM_TOKEN}}" > ~/.npmrc + yarn publish:react --registry=https://registry.npmjs.org/ diff --git a/package.json b/package.json index 7cd17b0..57aa050 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "scripts": { "test": "turbo run test", "prettier": "prettier . --check", - "publish:base": "yarn workspace @woohm402/eslint-config-base publish" + "publish:base": "yarn workspace @woohm402/eslint-config-base publish", + "publish:react": "yarn workspace @woohm402/eslint-config-react publish" }, "devDependencies": { "prettier": "3.2.5", diff --git a/packages/react/README.md b/packages/react/README.md new file mode 100644 index 0000000..f0c9d2e --- /dev/null +++ b/packages/react/README.md @@ -0,0 +1,5 @@ +[![NPM Version](https://img.shields.io/npm/v/%40woohm402%2Feslint-config-base)](https://www.npmjs.com/package/@woohm402/eslint-config-base) + +# @woohm402/eslint-config-base + +base configuration for JavaScript/TypeScript projects diff --git a/packages/react/__tests__/base.test.ts b/packages/react/__tests__/base.test.ts new file mode 100644 index 0000000..5f401ac --- /dev/null +++ b/packages/react/__tests__/base.test.ts @@ -0,0 +1,19 @@ +import { ESLint } from 'eslint'; +import { describe, it, expect } from 'vitest'; +import path from 'path'; + +const eslint = new ESLint({ overrideConfigFile: path.resolve(__dirname, '../index.js') }); + +describe('@woohm402/eslint-config-base', function () { + it('right', async function () { + const [result] = await eslint.lintFiles([`${__dirname}/right.tsx`]); + + expect(result.errorCount).toBe(0); + }); + + it('wrong', async function () { + const [result] = await eslint.lintFiles([`${__dirname}/wrong.tsx`]); + + expect(result.errorCount).toBe(1); + }); +}); diff --git a/packages/react/__tests__/right.tsx b/packages/react/__tests__/right.tsx new file mode 100644 index 0000000..9afc9e0 --- /dev/null +++ b/packages/react/__tests__/right.tsx @@ -0,0 +1,19 @@ +import { useEffect, useState } from 'react'; + +const fetchData = async (name: string) => new Promise((resolve) => setTimeout(() => resolve(name), 1000)); + +export const Component = ({ name }: { name: string }) => { + const [data, setData] = useState(); + + useEffect(() => { + let ignore = false; + + fetchData(name).then((data) => !ignore && setData(data)); + + return () => { + ignore = true; + }; + }, [name]); + + return
{data}
; +}; diff --git a/packages/react/__tests__/wrong.tsx b/packages/react/__tests__/wrong.tsx new file mode 100644 index 0000000..8f811f9 --- /dev/null +++ b/packages/react/__tests__/wrong.tsx @@ -0,0 +1,19 @@ +import { useEffect, useState } from 'react'; + +const fetchData = async (name: string) => new Promise((resolve) => setTimeout(() => resolve(name), 1000)); + +export const Component = ({ name }: { name: string }) => { + const [data, setData] = useState(); + + useEffect(() => { + let ignore = false; + + fetchData(name).then((data) => !ignore && setData(data)); + + return () => { + ignore = true; + }; + }, []); + + return
{data}
; +}; diff --git a/packages/react/index.d.ts b/packages/react/index.d.ts new file mode 100644 index 0000000..54d73fa --- /dev/null +++ b/packages/react/index.d.ts @@ -0,0 +1,5 @@ +import { ESLint } from 'eslint'; + +declare const eslintConfigBase: ESLint.Config; + +export = eslintConfigBase; diff --git a/packages/react/index.js b/packages/react/index.js new file mode 100644 index 0000000..01acd64 --- /dev/null +++ b/packages/react/index.js @@ -0,0 +1,16 @@ +import woohm402 from '@woohm402/eslint-config-base'; +import eslintPluginReactHooks from 'eslint-plugin-react-hooks'; +import { fixupPluginRules } from '@eslint/compat'; + +export default [ + ...woohm402, + { + plugins: { + 'react-hooks': fixupPluginRules(eslintPluginReactHooks), + }, + rules: { + ...eslintPluginReactHooks.configs.recommended.rules, + 'react-hooks/exhaustive-deps': 'error', + }, + }, +]; diff --git a/packages/react/package.json b/packages/react/package.json new file mode 100644 index 0000000..0454a6d --- /dev/null +++ b/packages/react/package.json @@ -0,0 +1,54 @@ +{ + "name": "@woohm402/eslint-config-react", + "version": "0.0.1", + "description": "Base config for TypeScript React", + "private": false, + "scripts": { + "test": "vitest run" + }, + "type": "module", + "main": "index.js", + "types": "index.d.ts", + "files": [ + "index.js", + "index.d.ts" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/woohm402/eslint-config-woohm402.git", + "directory": "packages/react" + }, + "keywords": [ + "eslint", + "eslintconfig" + ], + "author": "Hyunmin Woo (https://github.com/woohm402)", + "license": "MIT", + "bugs": { + "url": "https://github.com/woohm402/eslint-config-woohm402/issues" + }, + "homepage": "https://github.com/woohm402/eslint-config-woohm402#readme", + "dependencies": { + "@eslint/compat": "1.0.3", + "@woohm402/eslint-config-base": "0.1.0", + "eslint-plugin-react-hooks": "4.6.2" + }, + "peerDependencies": { + "@types/react": ">= 18", + "eslint": ">= 9", + "prettier": ">= 3", + "react": ">= 18", + "typescript": ">= 5" + }, + "devDependencies": { + "@types/eslint": "8.56.10", + "@types/node": "20.12.13", + "@types/react": "18.3.3", + "eslint": "9.3.0", + "typescript": "5.4.5", + "vitest": "1.6.0" + } +} diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json new file mode 100644 index 0000000..6b38a63 --- /dev/null +++ b/packages/react/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "types": ["node"], + "strict": true, + "esModuleInterop": true, + "jsx": "react-jsx" + }, + "include": ["__tests__/**/*"], + "exclude": ["node_modules"] +} diff --git a/packages/react/vitest.config.js b/packages/react/vitest.config.js new file mode 100644 index 0000000..0dfff65 --- /dev/null +++ b/packages/react/vitest.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + files: ['**/*.test.js'], + }, +}); diff --git a/yarn.lock b/yarn.lock index 9f97449..4f859e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -117,7 +117,7 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc" integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ== -"@eslint-community/eslint-plugin-eslint-comments@^4.3.0": +"@eslint-community/eslint-plugin-eslint-comments@4.3.0": version "4.3.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.3.0.tgz#e356a280764e14b1db9c94d0be7fab405431e2a6" integrity sha512-6e93KtgsndNkvwCCa07LOQJSwzzLLxwrFll3+huyFoiiQXWG0KBcmo0Q1bVgYQQDLfWOOZl2VPBsXqZL6vHIBQ== @@ -137,6 +137,11 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== +"@eslint/compat@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@eslint/compat/-/compat-1.0.3.tgz#6be44cf553a14a2f68fafb304818f7d824a7248f" + integrity sha512-9RaroPQaU2+SDcWav1YfuipwqnHccoiXZdUsicRQsQ/vH2wkEmRVcj344GapG/FnCeZRtqj0n6PshI+s9xkkAQ== + "@eslint/eslintrc@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" @@ -329,6 +334,19 @@ dependencies: undici-types "~5.26.4" +"@types/prop-types@*": + version "15.7.12" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" + integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== + +"@types/react@18.3.3": + version "18.3.3" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" + integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@typescript-eslint/eslint-plugin@7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz#f90f0914657ead08e1c75f66939c926edeab42dd" @@ -607,6 +625,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -685,6 +708,11 @@ eslint-plugin-prettier@5.1.3: prettier-linter-helpers "^1.0.0" synckit "^0.8.6" +eslint-plugin-react-hooks@4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" + integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== + eslint-plugin-simple-import-sort@12.1.0: version "12.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.0.tgz#8186ad55474d2f5c986a2f1bf70625a981e30d05"