{"_id":"@3o3/eslint-config","_rev":"2-ba0cf089f31811c5f9da9e87560d0125","name":"@3o3/eslint-config","dist-tags":{"latest":"1.0.0"},"versions":{"0.2.0":{"name":"@3o3/eslint-config","version":"0.2.0","license":"MIT","_id":"@3o3/eslint-config@0.2.0","maintainers":[{"name":"minseoksong","email":"minseoksong@jobis.co"}],"dist":{"shasum":"4716a49cab8350c86525bf53ddb2e024932d9ae7","tarball":"https://registry.npmjs.org/@3o3/eslint-config/-/eslint-config-0.2.0.tgz","fileCount":7,"integrity":"sha512-XpqbFEH1veZCV1BNrmmiFpsgBo0IGnypt+PdHIuMzpGLVyQhdHAWWRzcyaLBksltSgWxSSkSSf3igRsOzMT7DQ==","signatures":[{"sig":"MEUCIQC+qcQ6XPRJLWZvKucLynDdLUkVao3mOdCb1bcRmdZKbQIgXET8P+byYtYTBFpbuf0mNMZGEceqzOUSVrM2KjbXvyQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":17643},"main":"./src/index.js","type":"module","_from":"file:3o3-eslint-config-0.2.0.tgz","exports":{".":"./src/index.js","./all":"./src/all.js","./base":"./src/base.js","./docs":"./src/docs.js","./react":"./src/react.js","./package.json":"./package.json"},"_npmUser":{"name":"minseoksong","email":"minseoksong@jobis.co"},"_resolved":"/tmp/2711e06021dd11f93f1c8c230b3897fd/3o3-eslint-config-0.2.0.tgz","_integrity":"sha512-XpqbFEH1veZCV1BNrmmiFpsgBo0IGnypt+PdHIuMzpGLVyQhdHAWWRzcyaLBksltSgWxSSkSSf3igRsOzMT7DQ==","repository":{"url":"https://github.jobis.co/jobisnvillains/3o3_libraries","type":"git","directory":"configs/eslint-config"},"_npmVersion":"10.9.2","description":"3o3 공유 ESLint 설정 — 사용처에 따라 레이어(base/react/docs/all)를 골라 쓴다.","directories":{},"sideEffects":false,"_nodeVersion":"22.13.0","dependencies":{"globals":"^15.15.0","@eslint/js":"^9.39.4","typescript-eslint":"^8.60.0","eslint-plugin-jsdoc":"^63.0.2","eslint-plugin-react":"^7.37.5","eslint-plugin-tsdoc":"^0.5.2","eslint-plugin-import":"^2.32.0","@emotion/eslint-plugin":"^11.12.0","eslint-config-prettier":"^10.1.8","eslint-plugin-react-hooks":"^7.1.1","eslint-import-resolver-typescript":"^4.4.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"eslint":">=9","typescript":">=5"},"peerDependenciesMeta":{"typescript":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_0.2.0_1781074647326_0.5088559814705891","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@3o3/eslint-config","version":"1.0.0","description":"3o3 공유 ESLint 설정 — 사용처에 따라 레이어(base/react/docs/all)를 골라 쓴다.","type":"module","sideEffects":false,"main":"./src/index.js","exports":{".":"./src/index.js","./base":"./src/base.js","./react":"./src/react.js","./docs":"./src/docs.js","./all":"./src/all.js","./package.json":"./package.json"},"repository":{"type":"git","url":"https://github.jobis.co/jobisnvillains/3o3_libraries","directory":"configs/eslint-config"},"license":"MIT","dependencies":{"@emotion/eslint-plugin":"^11.12.0","@eslint/js":"^9.39.4","eslint-config-prettier":"^10.1.8","eslint-import-resolver-typescript":"^4.4.4","eslint-plugin-import":"^2.32.0","eslint-plugin-jsdoc":"^63.0.2","eslint-plugin-react":"^7.37.5","eslint-plugin-react-hooks":"^7.1.1","eslint-plugin-tsdoc":"^0.5.2","globals":"^15.15.0","typescript-eslint":"^8.60.0"},"peerDependencies":{"eslint":">=9","typescript":">=5"},"peerDependenciesMeta":{"typescript":{"optional":true}},"publishConfig":{"access":"public"},"_id":"@3o3/eslint-config@1.0.0","_integrity":"sha512-0Tue/hNQN45wBmGBDWatQINfB+2qFluU7GSlsbyHaV8IwrX144L3MUyqiUmMZZ6H+/MZxDGoCXdBvZKYJxEv8w==","_resolved":"/tmp/540c359ae2e000e99bcf91699a367e14/3o3-eslint-config-1.0.0.tgz","_from":"file:3o3-eslint-config-1.0.0.tgz","_nodeVersion":"24.16.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-0Tue/hNQN45wBmGBDWatQINfB+2qFluU7GSlsbyHaV8IwrX144L3MUyqiUmMZZ6H+/MZxDGoCXdBvZKYJxEv8w==","shasum":"95c756bdecf0a4204c56be6761e773dfa46d25c9","tarball":"https://registry.npmjs.org/@3o3/eslint-config/-/eslint-config-1.0.0.tgz","fileCount":8,"unpackedSize":19158,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCiW+aLCox0Yk0BgR72WBO8M+7rhnKRz2FyM7XlxorohgIgHZioZNSUz51fvpFcS6in5B+UhY3wSWxBj+O/v+D5B+c="}]},"_npmUser":{"name":"minseoksong","email":"minseoksong@jobis.co"},"directories":{},"maintainers":[{"name":"minseoksong","email":"minseoksong@jobis.co"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/eslint-config_1.0.0_1782880017994_0.545036077867104"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-10T06:57:27.193Z","modified":"2026-07-01T04:26:58.324Z","0.2.0":"2026-06-10T06:57:27.479Z","1.0.0":"2026-07-01T04:26:58.151Z"},"license":"MIT","repository":{"type":"git","url":"https://github.jobis.co/jobisnvillains/3o3_libraries","directory":"configs/eslint-config"},"description":"3o3 공유 ESLint 설정 — 사용처에 따라 레이어(base/react/docs/all)를 골라 쓴다.","maintainers":[{"name":"minseoksong","email":"minseoksong@jobis.co"}],"readme":"# @3o3/eslint-config\n\n3o3 공유 ESLint 설정(ESLint 9 flat config). **사용처에 따라 레이어를 골라** 쓴다.\n\n## 설치\n\n```sh\npnpm add -D @3o3/eslint-config eslint typescript\n```\n\n`eslint` 와 `typescript` 는 peerDependency, 나머지 플러그인(typescript-eslint,\neslint-plugin-react, react-hooks, import, @emotion, jsdoc, tsdoc, prettier)은 이\n패키지의 dependency 라 따로 설치할 필요가 없다.\n\n## 레이어\n\n| 레이어 | 내용 | 언제 |\n|---|---|---|\n| `base` | js + ts 공통(`@eslint/js` + `typescript-eslint` + `import`) + 3o3 하우스 규칙 | 모든 TS 코드(토대) |\n| `react` | `base` 위 React 델타(`eslint-plugin-react` + `react-hooks` + `@emotion`) | React 패키지/앱 |\n| `docs` | 공개 API 문서 완전성(`jsdoc` + `tsdoc`) — `src/**` 글롭, 내부는 파일 지시어로 opt-out | 공개 API 문서 강제 |\n| `all` | `base + react + prettier` 번들 | \"전부 켜기\" |\n| `prettier` | `eslint-config-prettier`(포매팅 충돌 규칙 off) | 항상 **마지막**에 스프레드 |\n\n`react` 는 `base` 위에 얹는 누적 델타다. 각 영역의 3o3 규칙을 이미 포함한다.\n전역 무시(dist/esm/비 ts·tsx)와 프로젝트 고유 규칙은 소비하는 쪽 config 에서 직접 둔다.\n\n## 사용법\n\n루트에 `eslint.config.mjs` 하나를 두는 **단일 설정**을 권장한다(이 모노레포도 동일).\n`defineConfig` + 문자열 `extends` 스타일(ESLint 가 미는 방식)을 기본으로 쓴다.\ndefault export 는 `configs` 맵을 가진 플러그인 형태(typescript-eslint /\neslint-plugin-react 와 동일)라 `extends: ['@3o3/<layer>']` 로 참조된다.\n\n```js\n// eslint.config.mjs  (React 포함 레포)\nimport { defineConfig } from 'eslint/config'\nimport threeo3 from '@3o3/eslint-config'\n\nexport default defineConfig([\n  // 전역 무시는 소비하는 쪽에서 직접 둔다(빌드 산출물 + 비 ts·tsx)\n  { ignores: ['**/dist/**', '**/esm/**', '**/*.{js,cjs,mjs,jsx,json}'] },\n  { plugins: { '@3o3': threeo3 }, extends: ['@3o3/base', '@3o3/react'] },\n  ...threeo3.docs(), // 공개 API 문서 검사(선택)\n  threeo3.prettier, // 항상 마지막\n])\n```\n\n```js\n// 플레인 TS 레포(React 없음) — react 레이어만 빼면 된다\nexport default defineConfig([\n  { ignores: ['**/dist/**', '**/esm/**', '**/*.{js,cjs,mjs,jsx,json}'] },\n  { plugins: { '@3o3': threeo3 }, extends: ['@3o3/base'] },\n  threeo3.prettier,\n])\n```\n\n프로젝트 고유 규칙은 마지막(프리티어 앞)에 flat-config 객체로 직접 얹는다:\n```js\n  { files: ['**/*.{ts,tsx}'], rules: { 'no-console': 'error' } },\n  { files: ['scripts/**'], rules: { '@typescript-eslint/no-explicit-any': 'off' } },\n```\n\n### 배열 스프레드 스타일 (named export)\n\n`extends` 대신 배열을 직접 펼쳐도 된다.\n\n```js\nimport { base, react, docs, prettier } from '@3o3/eslint-config'\n\nexport default [\n  { ignores: ['**/dist/**', '**/esm/**', '**/*.{js,cjs,mjs,jsx,json}'] },\n  ...base,\n  ...react,\n  ...docs(),\n  prettier,\n]\n```\n\n## docs 레이어 — 공개 API 문서 강제 (글롭 + 지시어 opt-out)\n\n`docs()` 는 `src/**` 의 ts/tsx 에서 **export 된 함수·상수·인터페이스에 문서 블록을\n요구**한다(`jsdoc/require-jsdoc`). 즉 **\"문서 필수가 기본값\"**.\n\n내부 전용 모듈(배럴로 공개 안 하는 헬퍼)은 파일 **맨 위 한 줄**로 제외한다:\n```ts\n/* eslint-disable jsdoc/require-jsdoc -- 비공개(내부) 모듈: 공개 API 아님 */\n```\n- `jsdoc/require-jsdoc` 하나만 끄면 docs 강제가 통째로 꺼진다(base/react 등은 그대로).\n- `tsdoc/syntax` 는 같이 적지 말 것 — 그 파일에 TSDoc 주석이 없으면 \"unused directive\"\n  경고가 난다.\n\n`files` 글롭은 옵션으로 바꿀 수 있다: `docs({ files: ['packages/**/src/**/*.{ts,tsx}'] })`.\n기본은 `['**/src/**/*.{ts,tsx}']`(test/spec·stories·d.ts·`_internal` 자동 제외).\n\n### 왜 이 방식인가 (과거 re-export fs 스캔 대비)\n\n- **에디터 즉시 반영** — 정적 글롭이라 배럴을 바꿔도 ESLint 서버 재시작이 필요 없다.\n  (스캔 방식은 공개 목록을 config 로드 때 한 번 계산·캐시해서, 배럴 변경이 에디터에\n  반영되려면 재시작이 필요했다.)\n- **모르게 빠지지 않음** — 기본이 \"문서 필수\"라, 새 공개 파일은 자동으로 강제 대상.\n  내부 제외는 코드에 지시어로 **명시**되어 코드리뷰에서 보인다.\n- **런타임 fs 작업 없음** — docs 설정이 순수 정적.\n\n## 설계 메모\n\n- **타입 인지 규칙 미사용**: `recommended`(not type-checked)만 켠다 →\n  `parserOptions.project` 가 필요 없어 어떤 레포에서도 그대로 동작한다.\n- **무시·프로젝트 규칙은 소비처 config 에서**: base/react 는 순수 룰 레이어라 무시\n  규칙을 갖지 않는다. 전역 무시(dist/esm 등)와 프로젝트 고유 규칙은 소비하는 쪽\n  `eslint.config` 에서 직접 둔다.\n- **공개/내부 구분은 위치·지시어로** : 재export 그래프(동적)가 아니라 `src/**` 글롭 +\n  파일 지시어(정적)로 판정 → 예측 가능하고 에디터에 실시간.\n","readmeFilename":"README.md"}