@simplysm/lint 13.0.84 → 13.0.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +222 -96
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,164 +1,290 @@
|
|
|
1
1
|
# @simplysm/lint
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Simplysm 프로젝트용 ESLint 설정과 커스텀 규칙 패키지. ESLint v9 flat config 기반.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 설치
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @simplysm/lint
|
|
9
|
-
# or
|
|
10
8
|
pnpm add @simplysm/lint
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
## 엔트리포인트
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- `eslint` >= 9
|
|
18
|
-
- `typescript` >= 5
|
|
19
|
-
- `typescript-eslint` >= 8
|
|
20
|
-
|
|
21
|
-
## Exports
|
|
22
|
-
|
|
23
|
-
| Export path | Description |
|
|
13
|
+
| Export 경로 | 설명 |
|
|
24
14
|
|---|---|
|
|
25
|
-
| `@simplysm/lint/eslint-
|
|
26
|
-
| `@simplysm/lint/eslint-
|
|
27
|
-
|
|
28
|
-
---
|
|
15
|
+
| `@simplysm/lint/eslint-recommended` | 권장 ESLint flat config 배열 (규칙 프리셋) |
|
|
16
|
+
| `@simplysm/lint/eslint-plugin` | 커스텀 ESLint 플러그인 (`@simplysm/*` 규칙) |
|
|
29
17
|
|
|
30
|
-
##
|
|
18
|
+
## 사용법
|
|
31
19
|
|
|
32
|
-
|
|
20
|
+
### 권장 설정 적용 (eslint-recommended)
|
|
33
21
|
|
|
34
|
-
|
|
22
|
+
프로젝트의 `eslint.config.js`에서 가져와 사용한다.
|
|
35
23
|
|
|
36
24
|
```typescript
|
|
37
|
-
// eslint.config.
|
|
38
|
-
import
|
|
25
|
+
// eslint.config.js
|
|
26
|
+
import eslintRecommended from "@simplysm/lint/eslint-recommended";
|
|
39
27
|
|
|
40
28
|
export default [
|
|
41
|
-
...
|
|
42
|
-
//
|
|
29
|
+
...eslintRecommended,
|
|
30
|
+
// 추가 설정 오버라이드
|
|
43
31
|
];
|
|
44
32
|
```
|
|
45
33
|
|
|
46
|
-
|
|
34
|
+
이 설정에는 아래의 모든 규칙이 사전 구성되어 있으므로 별도로 플러그인을 등록할 필요가 없다.
|
|
47
35
|
|
|
48
|
-
|
|
36
|
+
### 플러그인 단독 사용 (eslint-plugin)
|
|
49
37
|
|
|
50
|
-
|
|
38
|
+
커스텀 규칙만 개별적으로 사용하려면 플러그인을 직접 등록한다.
|
|
51
39
|
|
|
52
|
-
|
|
40
|
+
```typescript
|
|
41
|
+
import plugin from "@simplysm/lint/eslint-plugin";
|
|
53
42
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
43
|
+
export default [
|
|
44
|
+
{
|
|
45
|
+
plugins: {
|
|
46
|
+
"@simplysm": plugin,
|
|
47
|
+
},
|
|
48
|
+
rules: {
|
|
49
|
+
"@simplysm/no-hard-private": "error",
|
|
50
|
+
"@simplysm/no-subpath-imports-from-simplysm": "error",
|
|
51
|
+
"@simplysm/ts-no-throw-not-implemented-error": "warn",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
```
|
|
59
56
|
|
|
60
|
-
|
|
57
|
+
## 권장 설정 구성 (eslint-recommended)
|
|
61
58
|
|
|
62
|
-
|
|
59
|
+
`eslint-recommended`는 `defineConfig()`으로 구성된 flat config 배열이다. 파일 타입별로 다른 규칙 세트가 적용된다.
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
- `require-await`, `await-thenable`, `return-await` (in try-catch), `no-floating-promises`
|
|
66
|
-
- `no-shadow`, `no-unnecessary-condition`, `no-unnecessary-type-assertion`
|
|
67
|
-
- `prefer-reduce-type-parameter`, `prefer-return-this-type`, `prefer-readonly`
|
|
68
|
-
- `strict-boolean-expressions` (nullable boolean/object allowed)
|
|
69
|
-
- `no-misused-promises` (void return arguments and attributes allowed)
|
|
70
|
-
- `only-throw-error`, `no-array-delete`, `no-unused-expressions`
|
|
71
|
-
- `ban-ts-comment` (`ts-expect-error` allowed with description >= 3 chars)
|
|
72
|
-
- **Custom rules**: All JS custom rules plus `@simplysm/ts-no-throw-not-implemented-error` (warn).
|
|
61
|
+
### 글로벌 무시 패턴
|
|
73
62
|
|
|
74
|
-
|
|
63
|
+
```
|
|
64
|
+
**/node_modules/**, **/dist/**, **/.*/**, **/_*/**
|
|
65
|
+
```
|
|
75
66
|
|
|
76
|
-
|
|
67
|
+
### 공통 규칙 (JS/TS 모두 적용)
|
|
68
|
+
|
|
69
|
+
| 규칙 | 수준 | 설명 |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| `no-console` | error | `console.*` 사용 금지 |
|
|
72
|
+
| `no-warning-comments` | warn | TODO/FIXME 주석 경고 |
|
|
73
|
+
| `eqeqeq` | error | `===` 강제 (`== null`만 허용) |
|
|
74
|
+
| `no-self-compare` | error | 자기 자신과의 비교 방지 |
|
|
75
|
+
| `array-callback-return` | error | map/filter 콜백에서 return 누락 방지 |
|
|
76
|
+
|
|
77
|
+
### Node 빌트인 제한 규칙
|
|
78
|
+
|
|
79
|
+
| 규칙 | 대상 | 대안 |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `Buffer` 전역 변수 | `no-restricted-globals` | `Uint8Array` 또는 `BytesUtils` 사용 |
|
|
82
|
+
| `buffer` 모듈 import | `no-restricted-imports` | `Uint8Array` 또는 `BytesUtils` 사용 |
|
|
83
|
+
| `events` 모듈 import | `no-restricted-imports` | `@simplysm/core-common`의 `EventEmitter` 사용 |
|
|
84
|
+
| `eventemitter3` import | `no-restricted-imports` | `@simplysm/core-common`의 `EventEmitter` 사용 |
|
|
85
|
+
|
|
86
|
+
### JS 전용 규칙 (*.js, *.jsx)
|
|
87
|
+
|
|
88
|
+
공통 규칙에 추가로 `require-await`, `no-shadow`, `no-duplicate-imports`, `no-unused-expressions`, `no-undef`가 적용된다.
|
|
89
|
+
|
|
90
|
+
### TypeScript 전용 규칙 (*.ts, *.tsx)
|
|
91
|
+
|
|
92
|
+
공통 규칙에 추가로 TypeScript 전용 규칙이 적용된다. `typescript-eslint` 파서를 사용하며 프로젝트 타입 정보가 필요하다 (`project: true`).
|
|
93
|
+
|
|
94
|
+
| 규칙 | 수준 | 설명 |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `@typescript-eslint/require-await` | error | async 함수에 await 필수 |
|
|
97
|
+
| `@typescript-eslint/await-thenable` | error | thenable이 아닌 값에 await 금지 |
|
|
98
|
+
| `@typescript-eslint/return-await` | error | try-catch 내에서만 return await 허용 |
|
|
99
|
+
| `@typescript-eslint/no-floating-promises` | error | Promise를 반드시 await 또는 void 처리 |
|
|
100
|
+
| `@typescript-eslint/no-shadow` | error | 변수 섀도잉 금지 |
|
|
101
|
+
| `@typescript-eslint/no-unnecessary-condition` | error | 불필요한 조건 검사 금지 (상수 루프 허용) |
|
|
102
|
+
| `@typescript-eslint/no-unnecessary-type-assertion` | error | 불필요한 타입 단언 금지 |
|
|
103
|
+
| `@typescript-eslint/prefer-reduce-type-parameter` | error | reduce 타입 파라미터 사용 권장 |
|
|
104
|
+
| `@typescript-eslint/prefer-return-this-type` | error | this 반환 타입 사용 권장 |
|
|
105
|
+
| `@typescript-eslint/no-unused-expressions` | error | 미사용 표현식 금지 |
|
|
106
|
+
| `@typescript-eslint/strict-boolean-expressions` | error | 엄격한 boolean 표현식 (nullable boolean/object 허용) |
|
|
107
|
+
| `@typescript-eslint/ban-ts-comment` | error | `@ts-expect-error`만 설명 포함 시 허용 |
|
|
108
|
+
| `@typescript-eslint/prefer-readonly` | error | 재할당하지 않는 속성에 readonly 강제 |
|
|
109
|
+
| `@typescript-eslint/no-misused-promises` | error | void 콜백에 async 함수 전달 방지 (arguments/attributes 제외) |
|
|
110
|
+
| `@typescript-eslint/only-throw-error` | error | Error 객체만 throw 허용 |
|
|
111
|
+
| `@typescript-eslint/no-array-delete` | error | 배열에 delete 사용 금지 |
|
|
112
|
+
|
|
113
|
+
### 미사용 import 규칙
|
|
114
|
+
|
|
115
|
+
| 규칙 | 수준 | 설명 |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `unused-imports/no-unused-imports` | error | 미사용 import 자동 제거 |
|
|
118
|
+
| `unused-imports/no-unused-vars` | error | 미사용 변수 금지 (`_` 접두사 허용) |
|
|
119
|
+
|
|
120
|
+
### SolidJS 규칙 (*.ts, *.tsx)
|
|
121
|
+
|
|
122
|
+
| 규칙 | 수준 | 설명 |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| `solid/no-destructure` | error | Props 구조분해 금지 (반응성 손실 방지) |
|
|
125
|
+
| `solid/components-return-once` | error | 컴포넌트 단일 반환 강제 |
|
|
126
|
+
| `solid/jsx-no-duplicate-props` | error | 중복 props 금지 |
|
|
127
|
+
| `solid/jsx-no-undef` | error | 미정의 변수 참조 금지 (TS 지원) |
|
|
128
|
+
| `solid/no-react-deps` | error | React 의존성 배열 패턴 금지 |
|
|
129
|
+
| `solid/no-react-specific-props` | error | React 전용 props 금지 (className 등) |
|
|
130
|
+
| `solid/no-innerhtml` | error | innerHTML 사용 금지 (XSS 방지) |
|
|
131
|
+
| `solid/jsx-no-script-url` | error | `javascript:` URL 금지 |
|
|
132
|
+
| `solid/jsx-uses-vars` | error | JSX 변수 사용 추적 |
|
|
133
|
+
| `solid/prefer-for` | error | `.map()` 대신 `<For>` 컴포넌트 사용 |
|
|
134
|
+
| `solid/event-handlers` | error | 이벤트 핸들러 네이밍 규칙 |
|
|
135
|
+
| `solid/imports` | error | import 일관성 |
|
|
136
|
+
| `solid/style-prop` | error | style prop 형식 |
|
|
137
|
+
| `solid/self-closing-comp` | error | 셀프 클로징 태그 |
|
|
138
|
+
|
|
139
|
+
### Tailwind CSS 규칙 (*.ts, *.tsx)
|
|
140
|
+
|
|
141
|
+
`clsx` 템플릿 리터럴 태그를 지원한다.
|
|
142
|
+
|
|
143
|
+
| 규칙 | 수준 | 설명 |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `tailwindcss/classnames-order` | warn | 클래스 순서 자동 정렬 |
|
|
146
|
+
| `tailwindcss/enforces-negative-arbitrary-values` | error | 음수 임의 값 형식 통일 |
|
|
147
|
+
| `tailwindcss/enforces-shorthand` | error | 축약형 사용 권장 |
|
|
148
|
+
| `tailwindcss/no-contradicting-classname` | error | 충돌 클래스 금지 (`p-2 p-4` 등) |
|
|
149
|
+
| `tailwindcss/no-custom-classname` | error | Tailwind 외 커스텀 클래스 금지 |
|
|
150
|
+
| `tailwindcss/no-unnecessary-arbitrary-value` | error | 불필요한 임의 값 금지 |
|
|
151
|
+
|
|
152
|
+
### 테스트 파일 오버라이드
|
|
153
|
+
|
|
154
|
+
`**/tests/**`, `**/tests-e2e/**` 경로의 파일에는 다음 규칙이 완화된다:
|
|
77
155
|
|
|
78
156
|
- `no-console`: off
|
|
79
157
|
- `import/no-extraneous-dependencies`: off
|
|
80
158
|
- `@simplysm/ts-no-throw-not-implemented-error`: off
|
|
81
159
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- **eslint-plugin-solid** rules: `no-destructure`, `components-return-once`, `jsx-no-duplicate-props`, `jsx-no-undef`, `no-react-deps`, `no-react-specific-props`, `no-innerhtml`, `jsx-no-script-url`, `jsx-uses-vars`, `prefer-for`, `event-handlers`, `imports`, `style-prop`, `self-closing-comp`.
|
|
85
|
-
- **eslint-plugin-tailwindcss** rules: `classnames-order` (warn), `enforces-negative-arbitrary-values`, `enforces-shorthand`, `no-contradicting-classname`, `no-custom-classname`, `no-unnecessary-arbitrary-value`.
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## Custom Plugin
|
|
90
|
-
|
|
91
|
-
**`@simplysm/lint/eslint-plugin`**
|
|
92
|
-
|
|
93
|
-
An ESLint plugin object that exposes three custom rules under the `@simplysm` namespace.
|
|
160
|
+
## 커스텀 규칙 상세
|
|
94
161
|
|
|
95
|
-
|
|
96
|
-
import plugin from "@simplysm/lint/eslint-plugin";
|
|
97
|
-
|
|
98
|
-
// plugin.rules contains:
|
|
99
|
-
// - "no-hard-private"
|
|
100
|
-
// - "no-subpath-imports-from-simplysm"
|
|
101
|
-
// - "ts-no-throw-not-implemented-error"
|
|
102
|
-
```
|
|
162
|
+
### @simplysm/no-hard-private
|
|
103
163
|
|
|
104
|
-
|
|
164
|
+
ECMAScript `#private` 필드/메서드 대신 TypeScript `private _` 키워드 사용을 강제한다.
|
|
105
165
|
|
|
106
|
-
|
|
166
|
+
- **타입**: problem
|
|
167
|
+
- **자동 수정**: 지원 (fixable)
|
|
168
|
+
- **적용 대상**: JS, TS 모두
|
|
107
169
|
|
|
108
|
-
|
|
170
|
+
**감지 범위:**
|
|
171
|
+
- 클래스 필드 선언: `#field`
|
|
172
|
+
- 클래스 메서드 선언: `#method()`
|
|
173
|
+
- 클래스 접근자 선언: `accessor #field`
|
|
174
|
+
- 멤버 접근 표현식: `this.#field`
|
|
175
|
+
- 중첩 클래스 지원 (스택 구조)
|
|
109
176
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
177
|
+
**자동 수정 동작:**
|
|
178
|
+
1. `#name` -> `_name`으로 이름 변경
|
|
179
|
+
2. `private` 접근 제한자가 없으면 자동 추가
|
|
180
|
+
3. 데코레이터가 있으면 데코레이터 뒤에 `private` 삽입
|
|
181
|
+
4. 동일 이름의 멤버가 이미 존재하면 충돌 에러 보고 (수정 불가)
|
|
115
182
|
|
|
116
183
|
```typescript
|
|
117
184
|
// Bad
|
|
118
185
|
class Foo {
|
|
119
|
-
#
|
|
120
|
-
#
|
|
186
|
+
#bar = 1;
|
|
187
|
+
#baz() { return this.#bar; }
|
|
121
188
|
}
|
|
122
189
|
|
|
123
190
|
// Good
|
|
124
191
|
class Foo {
|
|
125
|
-
private
|
|
126
|
-
private
|
|
192
|
+
private _bar = 1;
|
|
193
|
+
private _baz() { return this._bar; }
|
|
127
194
|
}
|
|
128
195
|
```
|
|
129
196
|
|
|
130
|
-
|
|
197
|
+
**메시지:**
|
|
198
|
+
- `preferSoftPrivate`: `Hard private fields (#) are not allowed. Use the "private _" style instead.`
|
|
199
|
+
- `nameConflict`: `Cannot convert hard private field "#name" to "_name". A member with the same name already exists.`
|
|
200
|
+
|
|
201
|
+
### @simplysm/no-subpath-imports-from-simplysm
|
|
131
202
|
|
|
132
|
-
|
|
203
|
+
`@simplysm/*` 패키지의 `src/` 서브경로 import를 금지한다.
|
|
133
204
|
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
205
|
+
- **타입**: problem
|
|
206
|
+
- **자동 수정**: 지원 (fixable)
|
|
207
|
+
- **적용 대상**: JS, TS 모두
|
|
137
208
|
|
|
138
|
-
|
|
209
|
+
**감지 범위:**
|
|
210
|
+
- 정적 import: `import { x } from "@simplysm/pkg/src/..."`
|
|
211
|
+
- 동적 import: `import("@simplysm/pkg/src/...")`
|
|
212
|
+
- named re-export: `export { x } from "@simplysm/pkg/src/..."`
|
|
213
|
+
- 전체 re-export: `export * from "@simplysm/pkg/src/..."`
|
|
214
|
+
|
|
215
|
+
**자동 수정 동작:**
|
|
216
|
+
- `@simplysm/pkg/src/...` -> `@simplysm/pkg`로 경로 축약
|
|
139
217
|
|
|
140
218
|
```typescript
|
|
141
219
|
// Bad
|
|
142
|
-
import {
|
|
220
|
+
import { foo } from "@simplysm/core-common/src/utils/obj";
|
|
221
|
+
export { bar } from "@simplysm/solid/src/controls";
|
|
143
222
|
|
|
144
223
|
// Good
|
|
145
|
-
import {
|
|
224
|
+
import { foo } from "@simplysm/core-common";
|
|
225
|
+
export { bar } from "@simplysm/solid";
|
|
146
226
|
```
|
|
147
227
|
|
|
148
|
-
|
|
228
|
+
### @simplysm/ts-no-throw-not-implemented-error
|
|
229
|
+
|
|
230
|
+
`@simplysm/core-common`의 `NotImplementedError` 사용을 경고한다. 프로덕션 코드에서 미구현 부분을 감지하기 위한 규칙.
|
|
149
231
|
|
|
150
|
-
|
|
232
|
+
- **타입**: suggestion
|
|
233
|
+
- **자동 수정**: 미지원
|
|
234
|
+
- **적용 대상**: TS 전용 (타입 분석 필요)
|
|
235
|
+
- **기본 수준**: warn (테스트 파일에서는 off)
|
|
151
236
|
|
|
152
|
-
|
|
153
|
-
-
|
|
154
|
-
-
|
|
237
|
+
**감지 범위:**
|
|
238
|
+
- named import: `import { NotImplementedError } from "@simplysm/core-common"`
|
|
239
|
+
- aliased import: `import { NotImplementedError as NIE } from "@simplysm/core-common"`
|
|
240
|
+
- namespace import: `import * as CC from "@simplysm/core-common"` -> `new CC.NotImplementedError()`
|
|
241
|
+
- 동적 import (`await import(...)`)는 감지하지 않음
|
|
155
242
|
|
|
156
|
-
|
|
243
|
+
**보고 메시지:**
|
|
244
|
+
- 첫 번째 인자가 문자열이면 해당 문자열을 메시지로 표시
|
|
245
|
+
- 인자가 없으면 `"Not implemented"` 표시
|
|
157
246
|
|
|
158
247
|
```typescript
|
|
159
|
-
//
|
|
248
|
+
// Warning: "TODO: 나중에 구현"
|
|
249
|
+
throw new NotImplementedError("TODO: 나중에 구현");
|
|
250
|
+
|
|
251
|
+
// Warning: "Not implemented"
|
|
160
252
|
throw new NotImplementedError();
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## 유틸리티
|
|
256
|
+
|
|
257
|
+
### createRule
|
|
161
258
|
|
|
162
|
-
|
|
163
|
-
|
|
259
|
+
`@typescript-eslint/utils`의 `RuleCreator`를 래핑한 팩토리 함수. 커스텀 규칙 작성 시 사용한다.
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import { createRule } from "../utils/create-rule";
|
|
263
|
+
|
|
264
|
+
export default createRule({
|
|
265
|
+
name: "my-rule",
|
|
266
|
+
meta: {
|
|
267
|
+
type: "problem",
|
|
268
|
+
docs: { description: "규칙 설명" },
|
|
269
|
+
messages: { errorId: "에러 메시지" },
|
|
270
|
+
schema: [],
|
|
271
|
+
},
|
|
272
|
+
defaultOptions: [],
|
|
273
|
+
create(context) {
|
|
274
|
+
return {
|
|
275
|
+
// AST visitor
|
|
276
|
+
};
|
|
277
|
+
},
|
|
278
|
+
});
|
|
164
279
|
```
|
|
280
|
+
|
|
281
|
+
## 의존성
|
|
282
|
+
|
|
283
|
+
- `eslint` v9+
|
|
284
|
+
- `typescript-eslint` v8+
|
|
285
|
+
- `eslint-plugin-import` - import/export 규칙
|
|
286
|
+
- `eslint-plugin-unused-imports` - 미사용 import 자동 제거
|
|
287
|
+
- `eslint-plugin-solid` - SolidJS 규칙
|
|
288
|
+
- `eslint-plugin-tailwindcss` - Tailwind CSS 규칙
|
|
289
|
+
- `eslint-import-resolver-typescript` - TypeScript 경로 해석
|
|
290
|
+
- `globals` - 글로벌 변수 정의 (node, browser, es2024)
|